From 6e94182a3ed2ad367b370dbb852ecf8142770b0b Mon Sep 17 00:00:00 2001 From: Jason Paryani Date: Tue, 24 Feb 2015 11:22:43 -0800 Subject: [PATCH] Add bootstrap RPC methods This is the new way for initializing RPC connections. It replaces the deprecated restore functionality --- capnp/helpers/helpers.pxd | 1 + capnp/helpers/rpcHelper.h | 7 +++++++ capnp/includes/capnp_cpp.pxd | 1 + capnp/lib/capnp.pxd | 2 +- capnp/lib/capnp.pyx | 28 ++++++++++++++++++++++------ test/test_rpc.py | 14 ++++++++++++++ 6 files changed, 46 insertions(+), 7 deletions(-) diff --git a/capnp/helpers/helpers.pxd b/capnp/helpers/helpers.pxd index d0b1edc..28acaa1 100644 --- a/capnp/helpers/helpers.pxd +++ b/capnp/helpers/helpers.pxd @@ -30,6 +30,7 @@ cdef extern from "capnp/helpers/rpcHelper.h": Capability.Client restoreHelper(RpcSystem&, MessageReader&) Capability.Client restoreHelper(RpcSystem&, AnyPointer.Reader&) Capability.Client restoreHelper(RpcSystem&, AnyPointer.Builder&) + Capability.Client bootstrapHelper(RpcSystem&) RpcSystem makeRpcClientWithRestorer(TwoPartyVatNetwork&, PyRestorer&) PyPromise connectServer(TaskSet &, PyRestorer &, AsyncIoContext *, StringPtr) diff --git a/capnp/helpers/rpcHelper.h b/capnp/helpers/rpcHelper.h index a7d54bd..5ae53e3 100644 --- a/capnp/helpers/rpcHelper.h +++ b/capnp/helpers/rpcHelper.h @@ -73,6 +73,13 @@ capnp::Capability::Client restoreHelper(capnp::RpcSystem& client) { + capnp::MallocMessageBuilder hostIdMessage(8); + auto hostId = hostIdMessage.initRoot(); + hostId.setSide(capnp::rpc::twoparty::Side::SERVER); + return client.bootstrap(hostId); +} + template capnp::RpcSystem makeRpcClientWithRestorer( diff --git a/capnp/includes/capnp_cpp.pxd b/capnp/includes/capnp_cpp.pxd index 4e8dd8f..c246d0b 100644 --- a/capnp/includes/capnp_cpp.pxd +++ b/capnp/includes/capnp_cpp.pxd @@ -345,6 +345,7 @@ cdef extern from "capnp/rpc-twoparty.h" namespace " ::capnp": VoidPromise onDisconnect() VoidPromise onDrained() RpcSystem makeRpcServer(TwoPartyVatNetwork&, PyRestorer&) + RpcSystem makeRpcServerBootstrap"makeRpcServer"(TwoPartyVatNetwork&, Capability.Client) RpcSystem makeRpcClient(TwoPartyVatNetwork&) cdef extern from "capnp/dynamic.h" namespace " ::capnp": diff --git a/capnp/lib/capnp.pxd b/capnp/lib/capnp.pxd index 1f5ddea..d7e3360 100644 --- a/capnp/lib/capnp.pxd +++ b/capnp/lib/capnp.pxd @@ -1,6 +1,6 @@ from capnp.includes cimport capnp_cpp as capnp from capnp.includes cimport schema_cpp -from capnp.includes.capnp_cpp cimport Schema as C_Schema, StructSchema as C_StructSchema, InterfaceSchema as C_InterfaceSchema, EnumSchema as C_EnumSchema, ListSchema as C_ListSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue, Type as C_Type, DynamicList as C_DynamicList, SchemaParser as C_SchemaParser, ParsedSchema as C_ParsedSchema, VOID, ArrayPtr, StringPtr, String, StringTree, DynamicOrphan as C_DynamicOrphan, AnyPointer as C_DynamicObject, DynamicCapability as C_DynamicCapability, Request, Response, RemotePromise, PyPromise, VoidPromise, CallContext, PyRestorer, RpcSystem, makeRpcServer, makeRpcClient, Capability as C_Capability, TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, PromiseFulfillerPair as C_PromiseFulfillerPair, copyPromiseFulfillerPair, newPromiseAndFulfiller, PyArray, DynamicStruct_Builder +from capnp.includes.capnp_cpp cimport Schema as C_Schema, StructSchema as C_StructSchema, InterfaceSchema as C_InterfaceSchema, EnumSchema as C_EnumSchema, ListSchema as C_ListSchema, DynamicStruct as C_DynamicStruct, DynamicValue as C_DynamicValue, Type as C_Type, DynamicList as C_DynamicList, SchemaParser as C_SchemaParser, ParsedSchema as C_ParsedSchema, VOID, ArrayPtr, StringPtr, String, StringTree, DynamicOrphan as C_DynamicOrphan, AnyPointer as C_DynamicObject, DynamicCapability as C_DynamicCapability, Request, Response, RemotePromise, PyPromise, VoidPromise, CallContext, PyRestorer, RpcSystem, makeRpcServer, makeRpcServerBootstrap, makeRpcClient, Capability as C_Capability, TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, PromiseFulfillerPair as C_PromiseFulfillerPair, copyPromiseFulfillerPair, newPromiseAndFulfiller, PyArray, DynamicStruct_Builder from capnp.includes.schema_cpp cimport Node as C_Node, EnumNode as C_EnumNode from capnp.includes.types cimport * from capnp.helpers.non_circular cimport reraise_kj_exception diff --git a/capnp/lib/capnp.pyx b/capnp/lib/capnp.pyx index 47862c4..9a7efd2 100644 --- a/capnp/lib/capnp.pyx +++ b/capnp/lib/capnp.pyx @@ -2253,6 +2253,9 @@ cdef class TwoPartyClient: return self.restore(ref) + cpdef bootstrap(self) except +reraise_kj_exception: + return _CapabilityClient()._init(helpers.bootstrapHelper(deref(self.thisptr)), self) + cpdef on_disconnect(self) except +reraise_kj_exception: return _VoidPromise()._init(deref(self._network.thisptr).onDisconnect()) @@ -2263,12 +2266,18 @@ cdef class TwoPartyServer: cdef public _Restorer _restorer cdef public _AsyncIoStream _stream cdef object _port - cdef public object port_promise + cdef public object port_promise, _bootstrap cdef capnp.TaskSet * _task_set cdef capnp.ErrorHandler _error_handler - def __init__(self, socket, restorer, server_socket=None): - self._restorer = _convert_restorer(restorer) + def __init__(self, socket, restorer=None, server_socket=None, bootstrap=None): + if not restorer and not bootstrap: + raise KjException("You must provide either a bootstrap interface or a restorer (deperecated) to a server constructor.") + + cdef _InterfaceSchema schema + self._restorer = None + self._bootstrap = None + if isinstance(socket, basestring): self._connect(socket) else: @@ -2277,11 +2286,19 @@ cdef class TwoPartyServer: self._server_socket = server_socket self._port = 0 self._network = _TwoPartyVatNetwork()._init(self._stream, capnp.SERVER) - self.thisptr = new RpcSystem(makeRpcServer(deref(self._network.thisptr), deref(self._restorer.thisptr))) + + if bootstrap: + self._bootstrap = bootstrap + schema = bootstrap.schema + self.thisptr = new RpcSystem(makeRpcServerBootstrap(deref(self._network.thisptr), helpers.server_to_client(schema.thisptr, bootstrap))) + elif restorer: + self._restorer = _convert_restorer(restorer) + self.thisptr = new RpcSystem(makeRpcServer(deref(self._network.thisptr), deref(self._restorer.thisptr))) Py_INCREF(self._orig_stream) Py_INCREF(self._stream) Py_INCREF(self._restorer) + Py_INCREF(self._bootstrap) Py_INCREF(self._network) self._disconnect_promise = self.on_disconnect().then(self._decref) @@ -2292,6 +2309,7 @@ cdef class TwoPartyServer: self.port_promise = Promise()._init(helpers.connectServer(deref(self._task_set), deref(self._restorer.thisptr), loop.thisptr, temp_string)) def _decref(self): + Py_DECREF(self._bootstrap) Py_DECREF(self._restorer) Py_DECREF(self._orig_stream) Py_DECREF(self._stream) @@ -2318,8 +2336,6 @@ cdef class TwoPartyServer: else: return self._port - # TODO: add restore functionality here? - cdef class _AsyncIoStream: cdef Own[AsyncIoStream] thisptr diff --git a/test/test_rpc.py b/test/test_rpc.py index 6bae298..d288d04 100644 --- a/test/test_rpc.py +++ b/test/test_rpc.py @@ -86,3 +86,17 @@ def test_ez_rpc(): with pytest.raises(capnp.KjException): response = remote.wait() + +def test_simple_rpc_bootstrap(): + read, write = socket.socketpair(socket.AF_UNIX) + + server = capnp.TwoPartyServer(write, bootstrap=Server(100)) + client = capnp.TwoPartyClient(read) + + cap = client.bootstrap() + cap = cap.cast_as(test_capability_capnp.TestInterface) + + remote = cap.foo(i=5) + response = remote.wait() + + assert response.x == '125'