---
layout: slides
title: "Slides: What's Next for Cap'n Proto"
---

<!--===================================================================================-->

<section markdown="1" id="slides-cover">

What's Next for Cap'n Proto?

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Streaming">

Cap'n Proto supports streaming!

{% highlight capnp %}
interface FileStore {
  get @0 (name :Text, stream :Stream);
  put @1 (name :Text) -> (stream :Stream);
}

interface Stream {
  write @0 (data :Data);
  end @1 ();
}
{% endhighlight %}

But flow control is up to the app.

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Flow Control">

Let's build it in.

{% highlight capnp %}
interface Stream {
  write @0 (data :Data) -> bulk;
  end @1 ();
}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Realtime">

What about realtime streams?

{% highlight capnp %}
interface VideoCallStream {
  sendFrame @0 (frame :Frame) -> realtime;
}
{% endhighlight %}

<br>Best served on a UDP transport...

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Three-Party Handoff">

<img class="ph3" src="3ph.png">

Forwarded request.

Where does response go?

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Three-Party Handoff">

<img class="ph3" src="3ph-proxy.png">

Classic solution:

Proxy

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Three-Party Handoff">

<img class="ph3" src="3ph-redirect.png">

Classic solution:

Redirect

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Three-Party Handoff">

<img class="ph3" src="3ph-0rt.png">

Cap'n Proto:

3-Party Handoff

(aka 3PH)

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Three-Party Handoff">

<img class="ph3" src="3ph-0rt.png">

Cap'n Proto:

3-Party Handoff

(aka 3PH)

... gonna need UDP

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Three-Party Handoff">

<img class="ph3" src="3ph-0rt.png">

Cap'n Proto:

3-Party Handoff

(aka 3PH)

... gonna need UDP

... and 0-RT crypto

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Three-Party Handoff">

API: "Tail call"

{% highlight c++ %}
kj::Promise<void> myRpc(MyRpcContext context) override {
  // Begin sub-request.
  auto subRequest = someCapability.someRpcRequest();
  subRequest.setSomeParam(someValue);

  // Send as a tail call.
  return context.tailCall(kj::mv(subRequest));
}
{% endhighlight %}

Today: Will proxy<br>Future: 3PH

</section>

<!--===================================================================================-->

<section markdown="1" data-title="KJ TLS Bindings">

KJ client networking, no TLS:

{% highlight c++ %}
void send() {
  auto io = kj::setupAsyncIo();
  auto& network = io.provider->getNetwork();
  auto addr = network.parseAddress("capnproto.org", 80)
      .wait(io.waitScope);
  auto connection = addr->connect().wait(io.waitScope);
  connection->write("GET /", 5).wait(io.waitScope);
}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="KJ TLS Bindings">

KJ client networking with TLS:

{% highlight c++ %}
void send() {
  auto io = kj::setupAsyncIo();
  kj::TlsContext tls;
  auto network = tls.wrapNetwork(io.provider->getNetwork());
  auto addr = network->parseAddress("capnproto.org", 443)
      .wait(io.waitScope);
  auto connection = addr->connect().wait(io.waitScope);
  connection->write("GET /", 5).wait(io.waitScope);
}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="KJ TLS Bindings">

Diff:

{% highlight c++ %}
void send() {

  kj::TlsContext tls;
                 tls.wrapNetwork(                         );




}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="KJ TLS Bindings">

{% highlight c++ %}
void receive() {
  auto io = kj::setupAsyncIo();
  auto& network = io.provider->getNetwork();
  auto addr = network.parseAddress("*", 80)
      .wait(io.waitScope);
  auto listener = addr->listen();
  auto connection = listener->accept().wait(io.waitScope);
  connection->write("HTTP/1.1 404 Not Found\r\n\r\n", 26)
      .wait(io.waitScope);
}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="KJ TLS Bindings">

{% highlight c++ %}
void receive() {
  auto io = kj::setupAsyncIo();
  kj::TlsKeypair keypair { KEY_PEM_TEXT, CERT_PEM_TEXT };
  kj::TlsContext::Options options;
  options.defaultKeypair = keypair;
  kj::TlsContext tls(options);
  auto& network = io.provider->getNetwork();
  auto addr = network.parseAddress("*", 443).wait(io.waitScope);
  auto listener = tls.wrapPort(addr->listen());
  auto connection = listener->accept().wait(io.waitScope);
  connection->write("HTTP/1.1 404 Not Found\r\n\r\n", 26)
      .wait(io.waitScope);
}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="KJ TLS Bindings">

{% highlight c++ %}
void receive() {

  kj::TlsKeypair keypair { KEY_PEM_TEXT, CERT_PEM_TEXT };
  kj::TlsContext::Options options;
  options.defaultKeypair = keypair;
  kj::TlsContext tls(options);


                  tls.wrapPort(              );



}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="KJ HTTP Library">

{% highlight c++ %}
auto io = kj::setupAsyncIo();
kj::HttpHeaderTable headerTable;
auto client = kj::newHttpClient(
    *headerTable, io.provider->getNetwork());

kj::HttpHeaders headers(*headerTable);
auto response = client->request(
    kj::HttpMethod::GET, "http://capnproto.org", headers)
    .response.wait(io.waitScope);

KJ_ASSERT(response.statusCode == 200);
KJ_LOG(INFO, response.body->readAllText().wait(io.waitScope));
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="KJ HTTP Library">

Headers identified by small numbers.

{% highlight c++ %}
kj::HttpHeaderTable::Builder builder;
kj::HttpHeaderId userAgent = builder.add("User-Agent");
auto headerTable = builder.build();

kj::HttpHeaders headers(*headerTable);
headers.set(kj::HttpHeaderId::HOST, "capnproto.org");
headers.set(userAgent, "kj-http/0.6");
{% endhighlight %}

Header parsing is zero-copy.

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Designated Initializers">

Ugly imperative code:

{% highlight c++ %}
capnp::MallocMessageBuilder message;

auto root = message.initRoot<MyStruct>();
root.setFoo(123);
root.setBar("foo");
auto inner = root.initBaz();
inner.setQux(true);

capnp::writeMessageToFd(fd, message);
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Designated Initializers">

Nice declarative code:

{% highlight c++ %}
using namespace capnp::init;

capnp::MallocMessageBuilder message;
message.initRoot<MyStruct>(
  $foo = 123,
  $bar = "foo",
  $baz(
    $qux = true
  )
);
capnp::writeMessageToFd(fd, message);
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Designated Initializers">

Even better:

{% highlight c++ %}
using namespace capnp::init;

capnp::writeMessageToFd<MyStruct>(fd,
  $foo = 123,
  $bar = "foo",
  $baz(
    $qux = true
  )
);
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="Designated Initializers">

{% highlight c++ %}
struct {
  template <typename T>
  struct Setter {
    T value;
    template <typename U> void operator()(U& target) {
      target.setFoo(kj::fwd<T>(value));
    }
  };

  template <typename T>
  Setter<T> operator=(T&& value) {
    return { kj::fwd<T>(value) };
  }
} $foo;
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="POCS">

Not idiomatic:

{% highlight c++ %}
capnp::MallocMessageBuilder message;

MyStruct::Builder root = message.initRoot<MyStruct>();
root.setFoo(123);
root.setBar("foo");
InnerStruct::Builder inner = root.initBaz();
inner.setQux(true);

capnp::writeMessageToFd(fd, message);
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="POCS">

Plain Old C++ Structs?

{% highlight c++ %}
MyStruct root;
root.foo = 123;
root.bar = "foo";
InnerStruct inner;
inner.qux = true;
root.baz = kj::mv(inner);

capnp::writeMessageToFd(fd, message);
{% endhighlight %}

Caveat: No longer zero-copy.

</section>

<!--===================================================================================-->

<section markdown="1" data-title="POCS">

{% highlight c++ %}
capnp::MallocMessageBuilder message;
capnp::readMessageCopy(input, message);
auto root = message.getRoot<MyStruct>();
auto oldListOrphan = root.disownStructList();
auto oldList = oldListOrphan.getReader();
auto newList = root.initStructList(oldList.size() - 1);
for (auto i: kj::indices(newList)) {
  newList.setWithCaveats(i,
      oldList[i < indexToRemove ? i : i + 1]);
}
capnp::MallocMessageBuilder message2;
message2.setRoot(root.asReader());
capnp::writeMessage(output, message2);
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="POCS">

{% highlight c++ %}
auto root = capnp::readMessageCopy<MyStruct>(input);
root.structList.erase(indexToRemove);
capnp::writeMessageCopy(output, root);
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="JSON-HTTP Bridge">

{% highlight capnp %}
interface AddressBook {
  getPerson @0 (id :UInt32 $httpPath)
            -> (person :Person $httpBody(type = json))
      $http(method = get, route = "person");
  # GET /person/<id>
  # JSON response body

  updatePerson @1 (id :UInt32 $httpPath,
                   person :Person $httpBody(type = json));
      $http(method = put, route = "person");
  # PUT /person/<id>
  # JSON request body
}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="JSON-HTTP Bridge">

{% highlight capnp %}
addPerson @2 (person :Person $httpBody(type = json))
          -> (id :UInt32 $httpBody(type = jsonField));
    $http(method = post, route = "person");
# POST /person
# JSON request body
# JSON response body (object containing field `id`)

getAll @3 (page :UInt32 = 0 $httpQuery)
       -> (people: List(Person) $httpBody(type = json));
    $http(method = get);
# GET /?page=<num>
# Query is optional.
# JSAN (JSON array) response body.
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" data-title="JSON-HTTP Bridge">

{% highlight capnp %}
interface AddressBookService {
  getAddressBook @0 (key :String $httpPath)
                 -> (result :AddressBook $httpPipeline);
      $http(route = "book");
  # GET /book/JrpmUduyHd8uW3x3TOXn2g/person/123
  # Becomes:
  #     service.getAddressBook("JrpmUduyHd8uW3x3TOXn2g").send()
  #            .getResult().getPerson(123).send()
  #
  # GET /book/JrpmUduyHd8uW3x3TOXn2g
  # Becomes:
  #     service.getAddressBook("JrpmUduyHd8uW3x3TOXn2g").send()
  #            .getResult().getAll().send()
}
{% endhighlight %}

</section>

<!--===================================================================================-->

<section markdown="1" id="slides-cover">

Questions?

</section>
