capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

index.md (13054B)


      1 ---
      2 layout: slides
      3 title: "Slides: What's Next for Cap'n Proto"
      4 ---
      5 
      6 <!--===================================================================================-->
      7 
      8 <section markdown="1" id="slides-cover">
      9 
     10 What's Next for Cap'n Proto?
     11 
     12 </section>
     13 
     14 <!--===================================================================================-->
     15 
     16 <section markdown="1" data-title="Streaming">
     17 
     18 Cap'n Proto supports streaming!
     19 
     20 {% highlight capnp %}
     21 interface FileStore {
     22   get @0 (name :Text, stream :Stream);
     23   put @1 (name :Text) -> (stream :Stream);
     24 }
     25 
     26 interface Stream {
     27   write @0 (data :Data);
     28   end @1 ();
     29 }
     30 {% endhighlight %}
     31 
     32 But flow control is up to the app.
     33 
     34 </section>
     35 
     36 <!--===================================================================================-->
     37 
     38 <section markdown="1" data-title="Flow Control">
     39 
     40 Let's build it in.
     41 
     42 {% highlight capnp %}
     43 interface Stream {
     44   write @0 (data :Data) -> bulk;
     45   end @1 ();
     46 }
     47 {% endhighlight %}
     48 
     49 </section>
     50 
     51 <!--===================================================================================-->
     52 
     53 <section markdown="1" data-title="Realtime">
     54 
     55 What about realtime streams?
     56 
     57 {% highlight capnp %}
     58 interface VideoCallStream {
     59   sendFrame @0 (frame :Frame) -> realtime;
     60 }
     61 {% endhighlight %}
     62 
     63 <br>Best served on a UDP transport...
     64 
     65 </section>
     66 
     67 <!--===================================================================================-->
     68 
     69 <section markdown="1" data-title="Three-Party Handoff">
     70 
     71 <img class="ph3" src="3ph.png">
     72 
     73 Forwarded request.
     74 
     75 Where does response go?
     76 
     77 </section>
     78 
     79 <!--===================================================================================-->
     80 
     81 <section markdown="1" data-title="Three-Party Handoff">
     82 
     83 <img class="ph3" src="3ph-proxy.png">
     84 
     85 Classic solution:
     86 
     87 Proxy
     88 
     89 </section>
     90 
     91 <!--===================================================================================-->
     92 
     93 <section markdown="1" data-title="Three-Party Handoff">
     94 
     95 <img class="ph3" src="3ph-redirect.png">
     96 
     97 Classic solution:
     98 
     99 Redirect
    100 
    101 </section>
    102 
    103 <!--===================================================================================-->
    104 
    105 <section markdown="1" data-title="Three-Party Handoff">
    106 
    107 <img class="ph3" src="3ph-0rt.png">
    108 
    109 Cap'n Proto:
    110 
    111 3-Party Handoff
    112 
    113 (aka 3PH)
    114 
    115 </section>
    116 
    117 <!--===================================================================================-->
    118 
    119 <section markdown="1" data-title="Three-Party Handoff">
    120 
    121 <img class="ph3" src="3ph-0rt.png">
    122 
    123 Cap'n Proto:
    124 
    125 3-Party Handoff
    126 
    127 (aka 3PH)
    128 
    129 ... gonna need UDP
    130 
    131 </section>
    132 
    133 <!--===================================================================================-->
    134 
    135 <section markdown="1" data-title="Three-Party Handoff">
    136 
    137 <img class="ph3" src="3ph-0rt.png">
    138 
    139 Cap'n Proto:
    140 
    141 3-Party Handoff
    142 
    143 (aka 3PH)
    144 
    145 ... gonna need UDP
    146 
    147 ... and 0-RT crypto
    148 
    149 </section>
    150 
    151 <!--===================================================================================-->
    152 
    153 <section markdown="1" data-title="Three-Party Handoff">
    154 
    155 API: "Tail call"
    156 
    157 {% highlight c++ %}
    158 kj::Promise<void> myRpc(MyRpcContext context) override {
    159   // Begin sub-request.
    160   auto subRequest = someCapability.someRpcRequest();
    161   subRequest.setSomeParam(someValue);
    162 
    163   // Send as a tail call.
    164   return context.tailCall(kj::mv(subRequest));
    165 }
    166 {% endhighlight %}
    167 
    168 Today: Will proxy<br>Future: 3PH
    169 
    170 </section>
    171 
    172 <!--===================================================================================-->
    173 
    174 <section markdown="1" data-title="KJ TLS Bindings">
    175 
    176 KJ client networking, no TLS:
    177 
    178 {% highlight c++ %}
    179 void send() {
    180   auto io = kj::setupAsyncIo();
    181   auto& network = io.provider->getNetwork();
    182   auto addr = network.parseAddress("capnproto.org", 80)
    183       .wait(io.waitScope);
    184   auto connection = addr->connect().wait(io.waitScope);
    185   connection->write("GET /", 5).wait(io.waitScope);
    186 }
    187 {% endhighlight %}
    188 
    189 </section>
    190 
    191 <!--===================================================================================-->
    192 
    193 <section markdown="1" data-title="KJ TLS Bindings">
    194 
    195 KJ client networking with TLS:
    196 
    197 {% highlight c++ %}
    198 void send() {
    199   auto io = kj::setupAsyncIo();
    200   kj::TlsContext tls;
    201   auto network = tls.wrapNetwork(io.provider->getNetwork());
    202   auto addr = network->parseAddress("capnproto.org", 443)
    203       .wait(io.waitScope);
    204   auto connection = addr->connect().wait(io.waitScope);
    205   connection->write("GET /", 5).wait(io.waitScope);
    206 }
    207 {% endhighlight %}
    208 
    209 </section>
    210 
    211 <!--===================================================================================-->
    212 
    213 <section markdown="1" data-title="KJ TLS Bindings">
    214 
    215 Diff:
    216 
    217 {% highlight c++ %}
    218 void send() {
    219 
    220   kj::TlsContext tls;
    221                  tls.wrapNetwork(                         );
    222 
    223 
    224 
    225 
    226 }
    227 {% endhighlight %}
    228 
    229 </section>
    230 
    231 <!--===================================================================================-->
    232 
    233 <section markdown="1" data-title="KJ TLS Bindings">
    234 
    235 {% highlight c++ %}
    236 void receive() {
    237   auto io = kj::setupAsyncIo();
    238   auto& network = io.provider->getNetwork();
    239   auto addr = network.parseAddress("*", 80)
    240       .wait(io.waitScope);
    241   auto listener = addr->listen();
    242   auto connection = listener->accept().wait(io.waitScope);
    243   connection->write("HTTP/1.1 404 Not Found\r\n\r\n", 26)
    244       .wait(io.waitScope);
    245 }
    246 {% endhighlight %}
    247 
    248 </section>
    249 
    250 <!--===================================================================================-->
    251 
    252 <section markdown="1" data-title="KJ TLS Bindings">
    253 
    254 {% highlight c++ %}
    255 void receive() {
    256   auto io = kj::setupAsyncIo();
    257   kj::TlsKeypair keypair { KEY_PEM_TEXT, CERT_PEM_TEXT };
    258   kj::TlsContext::Options options;
    259   options.defaultKeypair = keypair;
    260   kj::TlsContext tls(options);
    261   auto& network = io.provider->getNetwork();
    262   auto addr = network.parseAddress("*", 443).wait(io.waitScope);
    263   auto listener = tls.wrapPort(addr->listen());
    264   auto connection = listener->accept().wait(io.waitScope);
    265   connection->write("HTTP/1.1 404 Not Found\r\n\r\n", 26)
    266       .wait(io.waitScope);
    267 }
    268 {% endhighlight %}
    269 
    270 </section>
    271 
    272 <!--===================================================================================-->
    273 
    274 <section markdown="1" data-title="KJ TLS Bindings">
    275 
    276 {% highlight c++ %}
    277 void receive() {
    278 
    279   kj::TlsKeypair keypair { KEY_PEM_TEXT, CERT_PEM_TEXT };
    280   kj::TlsContext::Options options;
    281   options.defaultKeypair = keypair;
    282   kj::TlsContext tls(options);
    283 
    284 
    285                   tls.wrapPort(              );
    286 
    287 
    288 
    289 }
    290 {% endhighlight %}
    291 
    292 </section>
    293 
    294 <!--===================================================================================-->
    295 
    296 <section markdown="1" data-title="KJ HTTP Library">
    297 
    298 {% highlight c++ %}
    299 auto io = kj::setupAsyncIo();
    300 kj::HttpHeaderTable headerTable;
    301 auto client = kj::newHttpClient(
    302     *headerTable, io.provider->getNetwork());
    303 
    304 kj::HttpHeaders headers(*headerTable);
    305 auto response = client->request(
    306     kj::HttpMethod::GET, "http://capnproto.org", headers)
    307     .response.wait(io.waitScope);
    308 
    309 KJ_ASSERT(response.statusCode == 200);
    310 KJ_LOG(INFO, response.body->readAllText().wait(io.waitScope));
    311 {% endhighlight %}
    312 
    313 </section>
    314 
    315 <!--===================================================================================-->
    316 
    317 <section markdown="1" data-title="KJ HTTP Library">
    318 
    319 Headers identified by small numbers.
    320 
    321 {% highlight c++ %}
    322 kj::HttpHeaderTable::Builder builder;
    323 kj::HttpHeaderId userAgent = builder.add("User-Agent");
    324 auto headerTable = builder.build();
    325 
    326 kj::HttpHeaders headers(*headerTable);
    327 headers.set(kj::HttpHeaderId::HOST, "capnproto.org");
    328 headers.set(userAgent, "kj-http/0.6");
    329 {% endhighlight %}
    330 
    331 Header parsing is zero-copy.
    332 
    333 </section>
    334 
    335 <!--===================================================================================-->
    336 
    337 <section markdown="1" data-title="Designated Initializers">
    338 
    339 Ugly imperative code:
    340 
    341 {% highlight c++ %}
    342 capnp::MallocMessageBuilder message;
    343 
    344 auto root = message.initRoot<MyStruct>();
    345 root.setFoo(123);
    346 root.setBar("foo");
    347 auto inner = root.initBaz();
    348 inner.setQux(true);
    349 
    350 capnp::writeMessageToFd(fd, message);
    351 {% endhighlight %}
    352 
    353 </section>
    354 
    355 <!--===================================================================================-->
    356 
    357 <section markdown="1" data-title="Designated Initializers">
    358 
    359 Nice declarative code:
    360 
    361 {% highlight c++ %}
    362 using namespace capnp::init;
    363 
    364 capnp::MallocMessageBuilder message;
    365 message.initRoot<MyStruct>(
    366   $foo = 123,
    367   $bar = "foo",
    368   $baz(
    369     $qux = true
    370   )
    371 );
    372 capnp::writeMessageToFd(fd, message);
    373 {% endhighlight %}
    374 
    375 </section>
    376 
    377 <!--===================================================================================-->
    378 
    379 <section markdown="1" data-title="Designated Initializers">
    380 
    381 Even better:
    382 
    383 {% highlight c++ %}
    384 using namespace capnp::init;
    385 
    386 capnp::writeMessageToFd<MyStruct>(fd,
    387   $foo = 123,
    388   $bar = "foo",
    389   $baz(
    390     $qux = true
    391   )
    392 );
    393 {% endhighlight %}
    394 
    395 </section>
    396 
    397 <!--===================================================================================-->
    398 
    399 <section markdown="1" data-title="Designated Initializers">
    400 
    401 {% highlight c++ %}
    402 struct {
    403   template <typename T>
    404   struct Setter {
    405     T value;
    406     template <typename U> void operator()(U& target) {
    407       target.setFoo(kj::fwd<T>(value));
    408     }
    409   };
    410 
    411   template <typename T>
    412   Setter<T> operator=(T&& value) {
    413     return { kj::fwd<T>(value) };
    414   }
    415 } $foo;
    416 {% endhighlight %}
    417 
    418 </section>
    419 
    420 <!--===================================================================================-->
    421 
    422 <section markdown="1" data-title="POCS">
    423 
    424 Not idiomatic:
    425 
    426 {% highlight c++ %}
    427 capnp::MallocMessageBuilder message;
    428 
    429 MyStruct::Builder root = message.initRoot<MyStruct>();
    430 root.setFoo(123);
    431 root.setBar("foo");
    432 InnerStruct::Builder inner = root.initBaz();
    433 inner.setQux(true);
    434 
    435 capnp::writeMessageToFd(fd, message);
    436 {% endhighlight %}
    437 
    438 </section>
    439 
    440 <!--===================================================================================-->
    441 
    442 <section markdown="1" data-title="POCS">
    443 
    444 Plain Old C++ Structs?
    445 
    446 {% highlight c++ %}
    447 MyStruct root;
    448 root.foo = 123;
    449 root.bar = "foo";
    450 InnerStruct inner;
    451 inner.qux = true;
    452 root.baz = kj::mv(inner);
    453 
    454 capnp::writeMessageToFd(fd, message);
    455 {% endhighlight %}
    456 
    457 Caveat: No longer zero-copy.
    458 
    459 </section>
    460 
    461 <!--===================================================================================-->
    462 
    463 <section markdown="1" data-title="POCS">
    464 
    465 {% highlight c++ %}
    466 capnp::MallocMessageBuilder message;
    467 capnp::readMessageCopy(input, message);
    468 auto root = message.getRoot<MyStruct>();
    469 auto oldListOrphan = root.disownStructList();
    470 auto oldList = oldListOrphan.getReader();
    471 auto newList = root.initStructList(oldList.size() - 1);
    472 for (auto i: kj::indices(newList)) {
    473   newList.setWithCaveats(i,
    474       oldList[i < indexToRemove ? i : i + 1]);
    475 }
    476 capnp::MallocMessageBuilder message2;
    477 message2.setRoot(root.asReader());
    478 capnp::writeMessage(output, message2);
    479 {% endhighlight %}
    480 
    481 </section>
    482 
    483 <!--===================================================================================-->
    484 
    485 <section markdown="1" data-title="POCS">
    486 
    487 {% highlight c++ %}
    488 auto root = capnp::readMessageCopy<MyStruct>(input);
    489 root.structList.erase(indexToRemove);
    490 capnp::writeMessageCopy(output, root);
    491 {% endhighlight %}
    492 
    493 </section>
    494 
    495 <!--===================================================================================-->
    496 
    497 <section markdown="1" data-title="JSON-HTTP Bridge">
    498 
    499 {% highlight capnp %}
    500 interface AddressBook {
    501   getPerson @0 (id :UInt32 $httpPath)
    502             -> (person :Person $httpBody(type = json))
    503       $http(method = get, route = "person");
    504   # GET /person/<id>
    505   # JSON response body
    506 
    507   updatePerson @1 (id :UInt32 $httpPath,
    508                    person :Person $httpBody(type = json));
    509       $http(method = put, route = "person");
    510   # PUT /person/<id>
    511   # JSON request body
    512 }
    513 {% endhighlight %}
    514 
    515 </section>
    516 
    517 <!--===================================================================================-->
    518 
    519 <section markdown="1" data-title="JSON-HTTP Bridge">
    520 
    521 {% highlight capnp %}
    522 addPerson @2 (person :Person $httpBody(type = json))
    523           -> (id :UInt32 $httpBody(type = jsonField));
    524     $http(method = post, route = "person");
    525 # POST /person
    526 # JSON request body
    527 # JSON response body (object containing field `id`)
    528 
    529 getAll @3 (page :UInt32 = 0 $httpQuery)
    530        -> (people: List(Person) $httpBody(type = json));
    531     $http(method = get);
    532 # GET /?page=<num>
    533 # Query is optional.
    534 # JSAN (JSON array) repsonse body.
    535 {% endhighlight %}
    536 
    537 </section>
    538 
    539 <!--===================================================================================-->
    540 
    541 <section markdown="1" data-title="JSON-HTTP Bridge">
    542 
    543 {% highlight capnp %}
    544 interface AddressBookService {
    545   getAddressBook @0 (key :String $httpPath)
    546                  -> (result :AddressBook $httpPipeline);
    547       $http(route = "book");
    548   # GET /book/JrpmUduyHd8uW3x3TOXn2g/person/123
    549   # Becomes:
    550   #     service.getAddressBook("JrpmUduyHd8uW3x3TOXn2g").send()
    551   #            .getResult().getPerson(123).send()
    552   #
    553   # GET /book/JrpmUduyHd8uW3x3TOXn2g
    554   # Becomes:
    555   #     service.getAddressBook("JrpmUduyHd8uW3x3TOXn2g").send()
    556   #            .getResult().getAll().send()
    557 }
    558 {% endhighlight %}
    559 
    560 </section>
    561 
    562 <!--===================================================================================-->
    563 
    564 <section markdown="1" id="slides-cover">
    565 
    566 Questions?
    567 
    568 </section>