Discussion:
[capnproto] Websockets server and TwoPartyVatNetwork starting point?
Asa
2018-09-19 05:58:07 UTC
Permalink
Are there any examples of the WebSocket service from compat/http.h that is
a self contained starting point? I am trying to get my head around how to
layer these components into a larger service. Basically I want to use rpc
over a websocket from the browser(via wasm) to a c++ service running a
TwoPartyVatNetwork. My current working implementation uses capnp
serialized structs in an async service(but not interfaces/rpc), from wasm
(compiled from c++) to a c++ asio websocket server. I separately brought
the ezrpc service up and extended the calc example, but now I want to
finish out the conversion and prototype how to replace my asio server.

Any pointers on where to look for more TwoPartyVatNetwork implementations
and/or docs would be great. Especially on how to save some state like a jwt
token ( via an auth capability?) in the open websocket, or if there is an
example somewhere of TwoPartyVatNetwork over websockets.

Thanks in advance.

Asa
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
'Kenton Varda' via Cap'n Proto
2018-09-19 23:16:11 UTC
Permalink
Hi Asa,

I don't think anyone has actually implemented TwoPartyVatNetwork over
WebSockets yet -- at least, I haven't heard of anyone doing it. It
certainly should be possible, though. First you'll need to decide if you
want to reuse WebSocket message framing at all, or just throw away the
frame boundaries and treat it as a byte stream. If you want to keep the
framing, you'd probably need to implement a custom VatNetwork, since
TwoPartyVatNetwork assumes an AsyncIoStream. If you go the byte stream
approach, then the thing you need to do is implement AsyncIoStream as a
wrapper around WebSocket. That should mostly be straightforward, assuming
familiarity with the KJ async framework. Once you have that, you can pass
it into TwoPartyVatNetwork.

If you're looking for example code that uses KJ HTTP, there is Sandstorm:


https://github.com/sandstorm-io/sandstorm/blob/master/src/sandstorm/gateway.h

However, that's real-world code, not a simple example. Unfortunately I
haven't written any samples yet... I'd like to write better documentation
for all of KJ soon...

Let me know if you have more specific questions, and please keep us updated
on your progress. :)

-Kenton
Post by Asa
Are there any examples of the WebSocket service from compat/http.h that is
a self contained starting point? I am trying to get my head around how to
layer these components into a larger service. Basically I want to use rpc
over a websocket from the browser(via wasm) to a c++ service running a
TwoPartyVatNetwork. My current working implementation uses capnp
serialized structs in an async service(but not interfaces/rpc), from wasm
(compiled from c++) to a c++ asio websocket server. I separately brought
the ezrpc service up and extended the calc example, but now I want to
finish out the conversion and prototype how to replace my asio server.
Any pointers on where to look for more TwoPartyVatNetwork implementations
and/or docs would be great. Especially on how to save some state like a jwt
token ( via an auth capability?) in the open websocket, or if there is an
example somewhere of TwoPartyVatNetwork over websockets.
Thanks in advance.
Asa
--
You received this message because you are subscribed to the Google Groups
"Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/group/capnproto.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
Asa Hammond
2018-09-19 23:48:51 UTC
Permalink
Awesome, thanks for the hints. I got TwoPartyVat working just now over
standard sockets, so I am beyond EZ! =) (really wasn't that bad).

One thing I need to layer in is an http /healthz endpoint so my
loadbalancer knows my service is alive. Prob super easy, but I am pretty
noob at kj::async. Basically how do I add a router into an ioContext? Is
it possible to have some http get at the same time as rpc on the same
port? My current implementation (uwebsockets) gives me cb for onOpen,
onConnection, onClose, and onMessage for the http and ws sides of things
separately, so I have some separation between these sides and the http
loadbalancer is happy cause it gets to talk to /healthz.

I'll look at your gnarly prod code and see what I can skim off into my
mind. =)

been a happy capnp serializer for 4 years or so at this point, nice stuff,
thanks!
Post by 'Kenton Varda' via Cap'n Proto
Hi Asa,
I don't think anyone has actually implemented TwoPartyVatNetwork over
WebSockets yet -- at least, I haven't heard of anyone doing it. It
certainly should be possible, though. First you'll need to decide if you
want to reuse WebSocket message framing at all, or just throw away the
frame boundaries and treat it as a byte stream. If you want to keep the
framing, you'd probably need to implement a custom VatNetwork, since
TwoPartyVatNetwork assumes an AsyncIoStream. If you go the byte stream
approach, then the thing you need to do is implement AsyncIoStream as a
wrapper around WebSocket. That should mostly be straightforward, assuming
familiarity with the KJ async framework. Once you have that, you can pass
it into TwoPartyVatNetwork.
https://github.com/sandstorm-io/sandstorm/blob/master/src/sandstorm/gateway.h
However, that's real-world code, not a simple example. Unfortunately I
haven't written any samples yet... I'd like to write better documentation
for all of KJ soon...
Let me know if you have more specific questions, and please keep us
updated on your progress. :)
-Kenton
Post by Asa
Are there any examples of the WebSocket service from compat/http.h that
is a self contained starting point? I am trying to get my head around how
to layer these components into a larger service. Basically I want to use
rpc over a websocket from the browser(via wasm) to a c++ service running a
TwoPartyVatNetwork. My current working implementation uses capnp
serialized structs in an async service(but not interfaces/rpc), from wasm
(compiled from c++) to a c++ asio websocket server. I separately brought
the ezrpc service up and extended the calc example, but now I want to
finish out the conversion and prototype how to replace my asio server.
Any pointers on where to look for more TwoPartyVatNetwork implementations
and/or docs would be great. Especially on how to save some state like a jwt
token ( via an auth capability?) in the open websocket, or if there is an
example somewhere of TwoPartyVatNetwork over websockets.
Thanks in advance.
Asa
--
You received this message because you are subscribed to the Google Groups
"Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an
Visit this group at https://groups.google.com/group/capnproto.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
'Kenton Varda' via Cap'n Proto
2018-09-21 19:36:25 UTC
Permalink
Hi Asa,

The canonical Cap'n Proto RPC protocol is not HTTP-based -- Cap'n Proto
messages are written directly to the socket. So, there's no way to add a
/healthz endpoint to the same port as RPC.

If you want to expose HTTP, you need to create a kj::HttpServer. Here's
some rough code to start with:

#include <kj/compat/http.h>

class MyHttpService: public kj::HttpService {
public:
// ... implement interface to handle HTTP requests ...
};

int main(int argc, char* argv) {
io = kj::setupAsyncIo();

// Register headers you are interested in.
kj::HttpHeaderTable::Builder htBuilder;
kj::HttpHeaderId myHeaderId = htBuilder.add("X-My-Header");
...
kj::Own<kj::HttpHeaderTable> headerTable = htBuilder.build();

// Create server.
MyHttpService myService;
kj::HttpServer server(io.provider->getTime(), *headerTable,
myService);

// Start listening.
auto listener = io.provider->getNetwork()
.parseAddress(argv[0]).wait(io.waitScope)->listen();
server.listenHttp(*listener).wait(io.waitScope);

// Will never get here; above will wait forever.
abort();
}

Your HttpService implementation can then accept WebSockets and potentially
adapt them as RPC channels...

-Kenton
Post by Asa Hammond
Awesome, thanks for the hints. I got TwoPartyVat working just now over
standard sockets, so I am beyond EZ! =) (really wasn't that bad).
One thing I need to layer in is an http /healthz endpoint so my
loadbalancer knows my service is alive. Prob super easy, but I am pretty
noob at kj::async. Basically how do I add a router into an ioContext? Is
it possible to have some http get at the same time as rpc on the same
port? My current implementation (uwebsockets) gives me cb for onOpen,
onConnection, onClose, and onMessage for the http and ws sides of things
separately, so I have some separation between these sides and the http
loadbalancer is happy cause it gets to talk to /healthz.
I'll look at your gnarly prod code and see what I can skim off into my
mind. =)
been a happy capnp serializer for 4 years or so at this point, nice stuff,
thanks!
Post by 'Kenton Varda' via Cap'n Proto
Hi Asa,
I don't think anyone has actually implemented TwoPartyVatNetwork over
WebSockets yet -- at least, I haven't heard of anyone doing it. It
certainly should be possible, though. First you'll need to decide if you
want to reuse WebSocket message framing at all, or just throw away the
frame boundaries and treat it as a byte stream. If you want to keep the
framing, you'd probably need to implement a custom VatNetwork, since
TwoPartyVatNetwork assumes an AsyncIoStream. If you go the byte stream
approach, then the thing you need to do is implement AsyncIoStream as a
wrapper around WebSocket. That should mostly be straightforward, assuming
familiarity with the KJ async framework. Once you have that, you can pass
it into TwoPartyVatNetwork.
https://github.com/sandstorm-io/sandstorm/blob/master/src/sandstorm/gateway.h
However, that's real-world code, not a simple example. Unfortunately I
haven't written any samples yet... I'd like to write better documentation
for all of KJ soon...
Let me know if you have more specific questions, and please keep us
updated on your progress. :)
-Kenton
Post by Asa
Are there any examples of the WebSocket service from compat/http.h that
is a self contained starting point? I am trying to get my head around how
to layer these components into a larger service. Basically I want to use
rpc over a websocket from the browser(via wasm) to a c++ service running a
TwoPartyVatNetwork. My current working implementation uses capnp
serialized structs in an async service(but not interfaces/rpc), from wasm
(compiled from c++) to a c++ asio websocket server. I separately brought
the ezrpc service up and extended the calc example, but now I want to
finish out the conversion and prototype how to replace my asio server.
Any pointers on where to look for more
TwoPartyVatNetwork implementations and/or docs would be great. Especially
on how to save some state like a jwt token ( via an auth capability?) in
the open websocket, or if there is an example somewhere of
TwoPartyVatNetwork over websockets.
Thanks in advance.
Asa
--
You received this message because you are subscribed to the Google
Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send
Visit this group at https://groups.google.com/group/capnproto.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
Ian Denhardt
2018-09-21 20:25:57 UTC
Permalink
Quoting 'Kenton Varda' via Cap'n Proto (2018-09-21 15:36:25)
Post by 'Kenton Varda' via Cap'n Proto
The canonical Cap'n Proto RPC protocol is not HTTP-based -- Cap'n Proto
messages are written directly to the socket. So, there's no way to add
a /healthz endpoint to the same port as RPC.
My take on how to do this: in your HTTP server, accept websocket
connections and use the URL/other information from the request to decide
what to supply as the capnproto bootstrap interface.

You mentioned wanting to be able to save state. I suggest having a look
at persistent.capnp.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
Asa Hammond
2018-09-21 21:32:20 UTC
Permalink
Thanks to both of you... I'll see when I can hack forward more on this
particular line. Looks very nice.
Post by Ian Denhardt
Quoting 'Kenton Varda' via Cap'n Proto (2018-09-21 15:36:25)
Post by 'Kenton Varda' via Cap'n Proto
The canonical Cap'n Proto RPC protocol is not HTTP-based -- Cap'n
Proto
Post by 'Kenton Varda' via Cap'n Proto
messages are written directly to the socket. So, there's no way to add
a /healthz endpoint to the same port as RPC.
My take on how to do this: in your HTTP server, accept websocket
connections and use the URL/other information from the request to decide
what to supply as the capnproto bootstrap interface.
You mentioned wanting to be able to save state. I suggest having a look
at persistent.capnp.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
Asa Hammond
2018-09-22 21:58:29 UTC
Permalink
Ok, that wasn't so bad. I now have an httpService that supports /healthz
and allows for websocket connections on /ws. Nice! Quite clean. Mostly
just copying around the test code and some spackle.
Now on to making TwoPartyVatNetwork work over it. I suppose I'll use the
AsyncIoStream approach(this websocket will be dedicated to rpc traffic).
More pointers? =) I'll start rooting around for asyncIoStream hacking
examples. Am I wrapping (and replacing) something like doWebSocket? and
passing that to TwoPartyServer.accept() ?
Post by Asa Hammond
Thanks to both of you... I'll see when I can hack forward more on this
particular line. Looks very nice.
Post by Ian Denhardt
Quoting 'Kenton Varda' via Cap'n Proto (2018-09-21 15:36:25)
Post by 'Kenton Varda' via Cap'n Proto
The canonical Cap'n Proto RPC protocol is not HTTP-based -- Cap'n
Proto
Post by 'Kenton Varda' via Cap'n Proto
messages are written directly to the socket. So, there's no way to
add
Post by 'Kenton Varda' via Cap'n Proto
a /healthz endpoint to the same port as RPC.
My take on how to do this: in your HTTP server, accept websocket
connections and use the URL/other information from the request to decide
what to supply as the capnproto bootstrap interface.
You mentioned wanting to be able to save state. I suggest having a look
at persistent.capnp.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
'Kenton Varda' via Cap'n Proto
2018-09-24 20:07:53 UTC
Permalink
Hi Asa,

You'll want to write a wrapper around kj::WebSocket that implements
kj::AsyncIoStream. The implementation of read() should call receive() on
the WebSocket and then copy message contents into the output buffer, until
at least minBytes bytes have been received. You may need to store the
leftovers in a temporary buffer for the next read() call. The
implementation of write() should delegate to the WebSocket's send() (should
be easy).

Then you can pass this AsyncIoStream implementation to
TwoPartyServer.accept().

-Kenton
Post by Asa Hammond
Ok, that wasn't so bad. I now have an httpService that supports /healthz
and allows for websocket connections on /ws. Nice! Quite clean. Mostly
just copying around the test code and some spackle.
Now on to making TwoPartyVatNetwork work over it. I suppose I'll use the
AsyncIoStream approach(this websocket will be dedicated to rpc traffic).
More pointers? =) I'll start rooting around for asyncIoStream hacking
examples. Am I wrapping (and replacing) something like doWebSocket? and
passing that to TwoPartyServer.accept() ?
Post by Asa Hammond
Thanks to both of you... I'll see when I can hack forward more on this
particular line. Looks very nice.
Post by Ian Denhardt
Quoting 'Kenton Varda' via Cap'n Proto (2018-09-21 15:36:25)
Post by 'Kenton Varda' via Cap'n Proto
The canonical Cap'n Proto RPC protocol is not HTTP-based -- Cap'n
Proto
Post by 'Kenton Varda' via Cap'n Proto
messages are written directly to the socket. So, there's no way to
add
Post by 'Kenton Varda' via Cap'n Proto
a /healthz endpoint to the same port as RPC.
My take on how to do this: in your HTTP server, accept websocket
connections and use the URL/other information from the request to decide
what to supply as the capnproto bootstrap interface.
You mentioned wanting to be able to save state. I suggest having a look
at persistent.capnp.
--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+***@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
Loading...