-
Notifications
You must be signed in to change notification settings - Fork 242
Description
I was just thinking about whether it would be possible to use Cap'n Proto RPC in a non-async application (in particular, I was interested in using unix domain sockets as transport). I've thrown together a simple example which I'd love to get your thoughts on: gist.
Observations:
- I tried to keep the dependencies to a minimum (in library size, rather than number of libraries)
- I'm a big fan of how all you need to create a two-party
VatNetworkisAsyncReadandAsyncWriteobjects, made the socket stuff surprisingly easy. - My biggest issue was dealing with polling the
RpcSystemon the client side. I get the generatedClientstruct contains some handle back to theRpcSystemso it can pass requests to it/receive responses from it. However, it would have been amazing to be able to get a future fromRpcSystemwhich is "run until you've nothing to do", so I don't have toselectwith thepromise. capnp_rpcis surprisingly heavy in binary-size (4.5% 28.0% 209.5KiB capnp_rpcfromcargo-bloatfor theserver, for example), not problematically huge, just a little surprising.- Client-side is also surprisingly heavy, but this time in
lib.rsitself:5.0% 30.8% 233.9KiB cprpc_blocking - Generally, more verbose documentation would be amazing for playing around with the library like this (e.g., what does
RpcSystemactually do when polled? what does it mean to "bootstrap" it?). Generally, I find the API and naming very confusing (though I get that some of this is inherited from the upstream project). This is especially fraught because so much of the machinery is generated from the schema file.
Specific questions:
- Am I doing anything wrong here? Obviously, this is an exceptionally simple example, so I know that this seeming to work doesn't necessarily validate the approach.
- I used async_io::block_on as the executor. I'm no expert, but this seemed to be among the simplest executors available for simple blocking usage (and I was already importing
async_iofor theAsynctrait anyways). - Obviously, this was written quickly and a lot of best-practices are missing, but how careful do I need to be about tearing down
RpcSystems nicely?
Finally (and this may be better for a different issue), I don't understand why there isn't an option to generate a more idiomatic version of the Server trait? Is it just that it would be too much work? I'm thinking something that would look like
impl Counter for Server {
fn count(&mut self) -> capnp::capability::Promise<u64, capnp::Error> {
// ... do something ...
Promise::ok(0)
}
}
rather than messing around with Params and Results objects. My guess is that the answer is "you'd just be hiding the boilerplate and potentially doing unnecessary work", but surely it's much more common to want access to all params and results?