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>