Removing deprecated Restorer and ezRestore references

- Not recommended to be used in new designs
- Just pollutes warning messages during compilation (hiding ones that
should be fixed)
- Updated test code to use bootstrap
- Sped up some of the test code that was just sleeping while waiting for
the server (now polling for the socket)
This commit is contained in:
Jacob Alexander
2019-10-14 23:19:39 -07:00
parent 12ddd743ef
commit f6dd08dda6
10 changed files with 70 additions and 368 deletions

View File

@@ -1,4 +1,4 @@
from capnp.includes.capnp_cpp cimport Maybe, DynamicStruct, Request, Response, PyPromise, VoidPromise, PyPromiseArray, RemotePromise, DynamicCapability, InterfaceSchema, EnumSchema, StructSchema, DynamicValue, Capability, RpcSystem, MessageBuilder, MessageReader, TwoPartyVatNetwork, PyRestorer, AnyPointer, DynamicStruct_Builder, WaitScope, AsyncIoContext, StringPtr, TaskSet, Timer from capnp.includes.capnp_cpp cimport Maybe, DynamicStruct, Request, Response, PyPromise, VoidPromise, PyPromiseArray, RemotePromise, DynamicCapability, InterfaceSchema, EnumSchema, StructSchema, DynamicValue, Capability, RpcSystem, MessageBuilder, MessageReader, TwoPartyVatNetwork, AnyPointer, DynamicStruct_Builder, WaitScope, AsyncIoContext, StringPtr, TaskSet, Timer
from capnp.includes.schema_cpp cimport ByteArray from capnp.includes.schema_cpp cimport ByteArray
@@ -27,15 +27,8 @@ cdef extern from "capnp/helpers/capabilityHelper.h":
VoidPromise convert_to_voidpromise(PyPromise&) VoidPromise convert_to_voidpromise(PyPromise&)
cdef extern from "capnp/helpers/rpcHelper.h": cdef extern from "capnp/helpers/rpcHelper.h":
Capability.Client restoreHelper(RpcSystem&)
Capability.Client restoreHelper(RpcSystem&, MessageBuilder&)
Capability.Client restoreHelper(RpcSystem&, MessageReader&)
Capability.Client restoreHelper(RpcSystem&, AnyPointer.Reader&)
Capability.Client restoreHelper(RpcSystem&, AnyPointer.Builder&)
Capability.Client bootstrapHelper(RpcSystem&) Capability.Client bootstrapHelper(RpcSystem&)
Capability.Client bootstrapHelperServer(RpcSystem&) Capability.Client bootstrapHelperServer(RpcSystem&)
RpcSystem makeRpcClientWithRestorer(TwoPartyVatNetwork&, PyRestorer&)
PyPromise connectServerRestorer(TaskSet &, PyRestorer &, AsyncIoContext *, StringPtr)
PyPromise connectServer(TaskSet &, Capability.Client, AsyncIoContext *, StringPtr) PyPromise connectServer(TaskSet &, Capability.Client, AsyncIoContext *, StringPtr)
cdef extern from "capnp/helpers/serialize.h": cdef extern from "capnp/helpers/serialize.h":

View File

@@ -12,8 +12,6 @@ cdef extern from "capnp/helpers/capabilityHelper.h":
PyRefCounter(PyObject *) PyRefCounter(PyObject *)
cdef extern from "capnp/helpers/rpcHelper.h": cdef extern from "capnp/helpers/rpcHelper.h":
cdef cppclass PyRestorer:
PyRestorer(PyObject *)
cdef cppclass ErrorHandler: cdef cppclass ErrorHandler:
pass pass

View File

@@ -6,73 +6,6 @@
#include "Python.h" #include "Python.h"
#include "capabilityHelper.h" #include "capabilityHelper.h"
extern "C" {
capnp::Capability::Client * call_py_restorer(PyObject *, capnp::AnyPointer::Reader &);
}
class PyRestorer final: public capnp::SturdyRefRestorer<capnp::AnyPointer> {
public:
PyRestorer(PyObject * _py_restorer): py_restorer(_py_restorer) {
// We don't need to incref/decref, since this C++ class will be owned by the Python wrapper class, and we'll make sure the python class doesn't refcount to 0 elsewhere.
// Py_INCREF(py_restorer);
}
// ~PyRestorer() {
// Py_DECREF(py_restorer);
// }
capnp::Capability::Client restore(capnp::AnyPointer::Reader objectId) override {
GILAcquire gil;
capnp::Capability::Client * ret = call_py_restorer(py_restorer, objectId);
check_py_error();
capnp::Capability::Client stack_ret(*ret);
delete ret;
return stack_ret;
}
private:
PyObject * py_restorer;
};
capnp::Capability::Client restoreHelper(capnp::RpcSystem<capnp::rpc::twoparty::SturdyRefHostId>& client, capnp::MessageBuilder & objectId) {
capnp::MallocMessageBuilder hostIdMessage(8);
auto hostId = hostIdMessage.initRoot<capnp::rpc::twoparty::SturdyRefHostId>();
hostId.setSide(capnp::rpc::twoparty::Side::SERVER);
return client.restore(hostId, objectId.getRoot<capnp::AnyPointer>());
}
capnp::Capability::Client restoreHelper(capnp::RpcSystem<capnp::rpc::twoparty::SturdyRefHostId>& client, capnp::MessageReader & objectId) {
capnp::MallocMessageBuilder hostIdMessage(8);
auto hostId = hostIdMessage.initRoot<capnp::rpc::twoparty::SturdyRefHostId>();
hostId.setSide(capnp::rpc::twoparty::Side::SERVER);
return client.restore(hostId, objectId.getRoot<capnp::AnyPointer>());
}
capnp::Capability::Client restoreHelper(capnp::RpcSystem<capnp::rpc::twoparty::SturdyRefHostId>& client, capnp::AnyPointer::Reader & objectId) {
capnp::MallocMessageBuilder hostIdMessage(8);
auto hostId = hostIdMessage.initRoot<capnp::rpc::twoparty::SturdyRefHostId>();
hostId.setSide(capnp::rpc::twoparty::Side::SERVER);
return client.restore(hostId, objectId);
}
capnp::Capability::Client restoreHelper(capnp::RpcSystem<capnp::rpc::twoparty::SturdyRefHostId>& client, capnp::AnyPointer::Builder & objectId) {
capnp::MallocMessageBuilder hostIdMessage(8);
auto hostId = hostIdMessage.initRoot<capnp::rpc::twoparty::SturdyRefHostId>();
hostId.setSide(capnp::rpc::twoparty::Side::SERVER);
return client.restore(hostId, objectId);
}
capnp::Capability::Client restoreHelper(capnp::RpcSystem<capnp::rpc::twoparty::SturdyRefHostId>& client) {
capnp::MallocMessageBuilder hostIdMessage(8);
auto hostId = hostIdMessage.initRoot<capnp::rpc::twoparty::SturdyRefHostId>();
hostId.setSide(capnp::rpc::twoparty::Side::SERVER);
capnp::MallocMessageBuilder blankMessage(8);
auto objectId = blankMessage.getRoot<capnp::AnyPointer>();
return client.restore(hostId, objectId);
}
capnp::Capability::Client bootstrapHelper(capnp::RpcSystem<capnp::rpc::twoparty::SturdyRefHostId>& client) { capnp::Capability::Client bootstrapHelper(capnp::RpcSystem<capnp::rpc::twoparty::SturdyRefHostId>& client) {
capnp::MallocMessageBuilder hostIdMessage(8); capnp::MallocMessageBuilder hostIdMessage(8);
auto hostId = hostIdMessage.initRoot<capnp::rpc::twoparty::SturdyRefHostId>(); auto hostId = hostIdMessage.initRoot<capnp::rpc::twoparty::SturdyRefHostId>();
@@ -87,63 +20,12 @@ capnp::Capability::Client bootstrapHelperServer(capnp::RpcSystem<capnp::rpc::two
return client.bootstrap(hostId); return client.bootstrap(hostId);
} }
template <typename SturdyRefHostId, typename ProvisionId,
typename RecipientId, typename ThirdPartyCapId, typename JoinAnswer>
capnp::RpcSystem<SturdyRefHostId> makeRpcClientWithRestorer(
capnp::VatNetwork<SturdyRefHostId, ProvisionId, RecipientId, ThirdPartyCapId, JoinAnswer>& network,
PyRestorer& restorer) {
using namespace capnp;
return RpcSystem<SturdyRefHostId>(network, restorer);
}
struct ServerContextRestorer {
kj::Own<kj::AsyncIoStream> stream;
capnp::TwoPartyVatNetwork network;
capnp::RpcSystem<capnp::rpc::twoparty::SturdyRefHostId> rpcSystem;
ServerContextRestorer(kj::Own<kj::AsyncIoStream>&& stream, capnp::SturdyRefRestorer<capnp::AnyPointer>& restorer)
: stream(kj::mv(stream)),
network(*this->stream, capnp::rpc::twoparty::Side::SERVER),
rpcSystem(makeRpcServer(network, restorer)) {}
};
class ErrorHandler : public kj::TaskSet::ErrorHandler { class ErrorHandler : public kj::TaskSet::ErrorHandler {
void taskFailed(kj::Exception&& exception) override { void taskFailed(kj::Exception&& exception) override {
kj::throwFatalException(kj::mv(exception)); kj::throwFatalException(kj::mv(exception));
} }
}; };
void acceptLoopRestorer(kj::TaskSet & tasks, PyRestorer & restorer, kj::Own<kj::ConnectionReceiver>&& listener) {
auto ptr = listener.get();
tasks.add(ptr->accept().then(kj::mvCapture(kj::mv(listener),
[&](kj::Own<kj::ConnectionReceiver>&& listener,
kj::Own<kj::AsyncIoStream>&& connection) {
acceptLoopRestorer(tasks, restorer, kj::mv(listener));
auto server = kj::heap<ServerContextRestorer>(kj::mv(connection), restorer);
// Arrange to destroy the server context when all references are gone, or when the
// EzRpcServer is destroyed (which will destroy the TaskSet).
tasks.add(server->network.onDisconnect().attach(kj::mv(server)));
})));
}
kj::Promise<PyObject *> connectServerRestorer(kj::TaskSet & tasks, PyRestorer & restorer, kj::AsyncIoContext * context, kj::StringPtr bindAddress) {
auto paf = kj::newPromiseAndFulfiller<unsigned int>();
auto portPromise = paf.promise.fork();
tasks.add(context->provider->getNetwork().parseAddress(bindAddress)
.then(kj::mvCapture(paf.fulfiller,
[&](kj::Own<kj::PromiseFulfiller<unsigned int>>&& portFulfiller,
kj::Own<kj::NetworkAddress>&& addr) {
auto listener = addr->listen();
portFulfiller->fulfill(listener->getPort());
acceptLoopRestorer(tasks, restorer, kj::mv(listener));
})));
return portPromise.addBranch().then([&](unsigned int port) { return PyLong_FromUnsignedLong(port); });
}
struct ServerContext { struct ServerContext {
kj::Own<kj::AsyncIoStream> stream; kj::Own<kj::AsyncIoStream> stream;

View File

@@ -6,7 +6,7 @@ cdef extern from "capnp/helpers/checkCompiler.h":
from libcpp cimport bool from libcpp cimport bool
from schema_cpp cimport Node, Data, StructNode, EnumNode, InterfaceNode, MessageBuilder, MessageReader, ReaderOptions from schema_cpp cimport Node, Data, StructNode, EnumNode, InterfaceNode, MessageBuilder, MessageReader, ReaderOptions
from capnp.helpers.non_circular cimport PythonInterfaceDynamicImpl, reraise_kj_exception, PyRefCounter, PyRestorer, PyEventPort, ErrorHandler from capnp.helpers.non_circular cimport PythonInterfaceDynamicImpl, reraise_kj_exception, PyRefCounter, PyEventPort, ErrorHandler
from capnp.includes.types cimport * from capnp.includes.types cimport *
cdef extern from "capnp/common.h" namespace " ::capnp": cdef extern from "capnp/common.h" namespace " ::capnp":
@@ -365,7 +365,6 @@ cdef extern from "capnp/rpc-twoparty.h" namespace " ::capnp":
TwoPartyVatNetwork(EventLoop &, AsyncIoStream& stream, Side, ReaderOptions) TwoPartyVatNetwork(EventLoop &, AsyncIoStream& stream, Side, ReaderOptions)
VoidPromise onDisconnect() VoidPromise onDisconnect()
VoidPromise onDrained() VoidPromise onDrained()
RpcSystem makeRpcServer(TwoPartyVatNetwork&, PyRestorer&)
RpcSystem makeRpcServerBootstrap"makeRpcServer"(TwoPartyVatNetwork&, Capability.Client) RpcSystem makeRpcServerBootstrap"makeRpcServer"(TwoPartyVatNetwork&, Capability.Client)
RpcSystem makeRpcClient(TwoPartyVatNetwork&) RpcSystem makeRpcClient(TwoPartyVatNetwork&)

View File

@@ -2,7 +2,7 @@
from capnp.includes cimport capnp_cpp as capnp from capnp.includes cimport capnp_cpp as capnp
from capnp.includes cimport schema_cpp 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, makeRpcServerBootstrap, makeRpcClient, Capability as C_Capability, TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, PromiseFulfillerPair as C_PromiseFulfillerPair, copyPromiseFulfillerPair, newPromiseAndFulfiller, PyArray, DynamicStruct_Builder, TwoWayPipe 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, RpcSystem, makeRpcServerBootstrap, makeRpcClient, Capability as C_Capability, TwoPartyVatNetwork as C_TwoPartyVatNetwork, Side, AsyncIoStream, Own, makeTwoPartyVatNetwork, PromiseFulfillerPair as C_PromiseFulfillerPair, copyPromiseFulfillerPair, newPromiseAndFulfiller, PyArray, DynamicStruct_Builder, TwoWayPipe
from capnp.includes.schema_cpp cimport Node as C_Node, EnumNode as C_EnumNode from capnp.includes.schema_cpp cimport Node as C_Node, EnumNode as C_EnumNode
from capnp.includes.types cimport * from capnp.includes.types cimport *
from capnp.helpers.non_circular cimport reraise_kj_exception from capnp.helpers.non_circular cimport reraise_kj_exception
@@ -103,14 +103,12 @@ cdef class _Schema:
cpdef as_struct(self) cpdef as_struct(self)
cpdef as_interface(self) cpdef as_interface(self)
cpdef as_enum(self) cpdef as_enum(self)
cpdef get_dependency(self, id)
cpdef get_proto(self) cpdef get_proto(self)
cdef class _InterfaceSchema: cdef class _InterfaceSchema:
cdef C_InterfaceSchema thisptr cdef C_InterfaceSchema thisptr
cdef object __method_names, __method_names_inherited, __methods, __methods_inherited cdef object __method_names, __method_names_inherited, __methods, __methods_inherited
cdef _init(self, C_InterfaceSchema other) cdef _init(self, C_InterfaceSchema other)
cpdef get_dependency(self, id)
cdef class _DynamicEnum: cdef class _DynamicEnum:
cdef capnp.DynamicEnum thisptr cdef capnp.DynamicEnum thisptr

View File

@@ -10,7 +10,6 @@
cimport cython cimport cython
from capnp.helpers.helpers cimport makeRpcClientWithRestorer
from capnp.helpers.helpers cimport AsyncIoStreamReadHelper from capnp.helpers.helpers cimport AsyncIoStreamReadHelper
from capnp.includes.capnp_cpp cimport AsyncIoStream, WaitScope from capnp.includes.capnp_cpp cimport AsyncIoStream, WaitScope
@@ -24,7 +23,6 @@ from cpython.buffer cimport PyBUF_SIMPLE, PyBUF_WRITABLE
from types import ModuleType as _ModuleType from types import ModuleType as _ModuleType
import os as _os import os as _os
import sys as _sys import sys as _sys
import imp as _imp
import traceback as _traceback import traceback as _traceback
from functools import partial as _partial from functools import partial as _partial
import warnings as _warnings import warnings as _warnings
@@ -120,17 +118,6 @@ cdef public VoidPromise * call_server_method(PyObject * _server, char * _method_
return NULL return NULL
cdef public C_Capability.Client * call_py_restorer(PyObject * _restorer, C_DynamicObject.Reader & _reader) except * with gil:
restorer = <object>_restorer
reader = _DynamicObjectReader()._init(_reader, None)
ret = restorer._restore(reader)
cdef _DynamicCapabilityServer server = ret
cdef _InterfaceSchema schema = ret.schema
return new C_Capability.Client(helpers.server_to_client(schema.thisptr, <PyObject *>server))
cdef public convert_array_pyobject(PyArray & arr) with gil: cdef public convert_array_pyobject(PyArray & arr) with gil:
return [<object>arr[i] for i in range(arr.size())] return [<object>arr[i] for i in range(arr.size())]
@@ -2233,21 +2220,6 @@ cdef class _CapabilityClient:
s = schema s = schema
return _DynamicCapabilityClient()._init(self.thisptr.castAs(s.thisptr), self._parent) return _DynamicCapabilityClient()._init(self.thisptr.castAs(s.thisptr), self._parent)
cdef class _Restorer:
cdef PyRestorer * thisptr
cdef public object restore, _parent
def __init__(self, restore, parent=None):
self.thisptr = new PyRestorer(<PyObject*>self)
self.restore = restore
self._parent = parent
def __dealloc__(self):
del self.thisptr
def _restore(self, obj):
return self.restore(obj)
cdef class _TwoPartyVatNetwork: cdef class _TwoPartyVatNetwork:
cdef Own[C_TwoPartyVatNetwork] thisptr cdef Own[C_TwoPartyVatNetwork] thisptr
cdef _AsyncIoStream stream cdef _AsyncIoStream stream
@@ -2264,27 +2236,14 @@ cdef class _TwoPartyVatNetwork:
cpdef on_disconnect(self) except +reraise_kj_exception: cpdef on_disconnect(self) except +reraise_kj_exception:
return _VoidPromise()._init(deref(self.thisptr).onDisconnect(), self) return _VoidPromise()._init(deref(self.thisptr).onDisconnect(), self)
cdef _Restorer _convert_restorer(restorer):
if isinstance(restorer, _RestorerImpl):
return _Restorer(restorer._restore, restorer)
elif type(restorer) is _Restorer:
return restorer
elif hasattr(restorer, 'restore'):
return _Restorer(restorer.restore, restorer)
elif callable(restorer):
return _Restorer(restorer)
else:
raise KjException("Restorer object ({}) isn't able to be used as a restore".format(str(restorer)))
cdef class TwoPartyClient: cdef class TwoPartyClient:
cdef RpcSystem * thisptr cdef RpcSystem * thisptr
cdef public _TwoPartyVatNetwork _network cdef public _TwoPartyVatNetwork _network
cdef public object _orig_stream cdef public object _orig_stream
cdef public _Restorer _restorer
cdef public _AsyncIoStream _stream cdef public _AsyncIoStream _stream
cdef public _TwoWayPipe _pipe cdef public _TwoWayPipe _pipe
def __init__(self, socket=None, restorer=None, traversal_limit_in_words=None, nesting_limit=None): def __init__(self, socket=None, traversal_limit_in_words=None, nesting_limit=None):
if isinstance(socket, basestring): if isinstance(socket, basestring):
socket = self._connect(socket) socket = self._connect(socket)
@@ -2299,15 +2258,7 @@ cdef class TwoPartyClient:
self._pipe = _TwoWayPipe() self._pipe = _TwoWayPipe()
self._network = _TwoPartyVatNetwork()._init_pipe(self._pipe, capnp.CLIENT, opts) self._network = _TwoPartyVatNetwork()._init_pipe(self._pipe, capnp.CLIENT, opts)
if restorer is None: self.thisptr = new RpcSystem(makeRpcClient(deref(self._network.thisptr)))
self.thisptr = new RpcSystem(makeRpcClient(deref(self._network.thisptr)))
self._restorer = None
else:
_warnings.warn('Restorers are deprecated. Please use the new bootstrap methods.', UserWarning)
self._restorer = _convert_restorer(restorer)
self.thisptr = new RpcSystem(makeRpcClientWithRestorer(deref(self._network.thisptr), deref(self._restorer.thisptr)))
Py_INCREF(self._restorer)
if self._orig_stream: if self._orig_stream:
Py_INCREF(self._orig_stream) Py_INCREF(self._orig_stream)
Py_INCREF(self._stream) Py_INCREF(self._stream)
@@ -2355,47 +2306,6 @@ cdef class TwoPartyClient:
sock.setsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1) sock.setsockopt(_socket.IPPROTO_TCP, _socket.TCP_NODELAY, 1)
return sock return sock
cpdef restore(self, objectId) except +reraise_kj_exception:
_warnings.warn('Restorers are deprecated. Please use the new bootstrap methods.', UserWarning)
cdef _MessageBuilder builder
cdef _MessageReader reader
cdef _DynamicObjectBuilder object_builder
cdef _DynamicObjectReader object_reader
if objectId is None:
return _CapabilityClient()._init(helpers.restoreHelper(deref(self.thisptr)), self)
elif type(objectId) is _DynamicObjectBuilder:
object_builder = objectId
return _CapabilityClient()._init(helpers.restoreHelper(deref(self.thisptr), deref(object_builder.thisptr)), self)
elif type(objectId) is _DynamicObjectReader:
object_reader = objectId
return _CapabilityClient()._init(helpers.restoreHelper(deref(self.thisptr), object_reader.thisptr), self)
else:
if not hasattr(objectId, 'is_root'):
raise KjException("objectId was not a valid Cap'n Proto struct")
if not objectId.is_root:
raise KjException("objectId must be the root of a Cap'n Proto message, ie. addressbook_capnp.Person.new_message()")
try:
builder = objectId._parent
except:
reader = objectId._parent
if builder is not None:
return _CapabilityClient()._init(helpers.restoreHelper(deref(self.thisptr), deref(builder.thisptr)), self)
elif reader is not None:
return _CapabilityClient()._init(helpers.restoreHelper(deref(self.thisptr), deref(reader.thisptr)), self)
else:
raise KjException("objectId unexpectedly was not convertible to the proper type")
cpdef ez_restore(self, textId) except +reraise_kj_exception:
# ez-rpc from the C++ API uses Text under the hood
ref = _MallocMessageBuilder().get_root_as_any()
# objectId is an AnyPointer, so we have a special method for setting it to text
ref.set_as_text(textId)
return self.restore(ref)
cpdef bootstrap(self) except +reraise_kj_exception: cpdef bootstrap(self) except +reraise_kj_exception:
return _CapabilityClient()._init(helpers.bootstrapHelper(deref(self.thisptr)), self) return _CapabilityClient()._init(helpers.bootstrapHelper(deref(self.thisptr)), self)
@@ -2406,7 +2316,6 @@ cdef class TwoPartyServer:
cdef RpcSystem * thisptr cdef RpcSystem * thisptr
cdef public _TwoPartyVatNetwork _network cdef public _TwoPartyVatNetwork _network
cdef public object _orig_stream, _server_socket, _disconnect_promise cdef public object _orig_stream, _server_socket, _disconnect_promise
cdef public _Restorer _restorer
cdef public _AsyncIoStream _stream cdef public _AsyncIoStream _stream
cdef public _TwoWayPipe _pipe cdef public _TwoWayPipe _pipe
cdef object _port cdef object _port
@@ -2414,18 +2323,17 @@ cdef class TwoPartyServer:
cdef capnp.TaskSet * _task_set cdef capnp.TaskSet * _task_set
cdef capnp.ErrorHandler _error_handler cdef capnp.ErrorHandler _error_handler
def __init__(self, socket=None, restorer=None, server_socket=None, bootstrap=None, def __init__(self, socket=None, server_socket=None, bootstrap=None,
traversal_limit_in_words=None, nesting_limit=None): traversal_limit_in_words=None, nesting_limit=None):
if not restorer and not bootstrap: if not bootstrap:
raise KjException("You must provide either a bootstrap interface or a restorer (deperecated) to a server constructor.") raise KjException("You must provide a bootstrap interface to a server constructor.")
cdef _InterfaceSchema schema cdef _InterfaceSchema schema
cdef schema_cpp.ReaderOptions opts = make_reader_opts(traversal_limit_in_words, nesting_limit) cdef schema_cpp.ReaderOptions opts = make_reader_opts(traversal_limit_in_words, nesting_limit)
self._restorer = None
self._bootstrap = None self._bootstrap = None
if isinstance(socket, basestring): if isinstance(socket, basestring):
self._connect(socket, restorer, bootstrap) self._connect(socket, bootstrap)
return return
self._orig_stream = socket self._orig_stream = socket
@@ -2444,12 +2352,7 @@ cdef class TwoPartyServer:
self._bootstrap = bootstrap self._bootstrap = bootstrap
schema = bootstrap.schema schema = bootstrap.schema
self.thisptr = new RpcSystem(makeRpcServerBootstrap(deref(self._network.thisptr), helpers.server_to_client(schema.thisptr, <PyObject *>bootstrap))) self.thisptr = new RpcSystem(makeRpcServerBootstrap(deref(self._network.thisptr), helpers.server_to_client(schema.thisptr, <PyObject *>bootstrap)))
elif restorer:
_warnings.warn('Restorers are deprecated. Please use the new bootstrap methods.', UserWarning)
self._restorer = _convert_restorer(restorer)
self.thisptr = new RpcSystem(makeRpcServer(deref(self._network.thisptr), deref(self._restorer.thisptr)))
Py_INCREF(self._restorer)
Py_INCREF(self._orig_stream) Py_INCREF(self._orig_stream)
Py_INCREF(self._stream) Py_INCREF(self._stream)
Py_INCREF(self._pipe) Py_INCREF(self._pipe)
@@ -2479,23 +2382,19 @@ cdef class TwoPartyServer:
len(data) len(data)
).wait(self._pipe._event_loop.thisptr.waitScope) ).wait(self._pipe._event_loop.thisptr.waitScope)
cpdef _connect(self, host_string, restorer, bootstrap): cpdef _connect(self, host_string, bootstrap):
cdef _InterfaceSchema schema cdef _InterfaceSchema schema
cdef _EventLoop loop = C_DEFAULT_EVENT_LOOP_GETTER() cdef _EventLoop loop = C_DEFAULT_EVENT_LOOP_GETTER()
cdef capnp.StringPtr temp_string = capnp.StringPtr(<char*>host_string, len(host_string)) cdef capnp.StringPtr temp_string = capnp.StringPtr(<char*>host_string, len(host_string))
self._task_set = new capnp.TaskSet(self._error_handler) self._task_set = new capnp.TaskSet(self._error_handler)
if restorer:
self._restorer = _convert_restorer(restorer) self._bootstrap = bootstrap
self.port_promise = Promise()._init(helpers.connectServerRestorer(deref(self._task_set), deref(self._restorer.thisptr), loop.thisptr, temp_string)) Py_INCREF(self._bootstrap)
else: schema = bootstrap.schema
self._bootstrap = bootstrap self.port_promise = Promise()._init(helpers.connectServer(deref(self._task_set), helpers.server_to_client(schema.thisptr, <PyObject *>bootstrap), loop.thisptr, temp_string))
Py_INCREF(self._bootstrap)
schema = bootstrap.schema
self.port_promise = Promise()._init(helpers.connectServer(deref(self._task_set), helpers.server_to_client(schema.thisptr, <PyObject *>bootstrap), loop.thisptr, temp_string))
def _decref(self): def _decref(self):
Py_DECREF(self._bootstrap) Py_DECREF(self._bootstrap)
Py_DECREF(self._restorer)
Py_INCREF(self._pipe) Py_INCREF(self._pipe)
Py_DECREF(self._orig_stream) Py_DECREF(self._orig_stream)
Py_DECREF(self._stream) Py_DECREF(self._stream)
@@ -2589,11 +2488,6 @@ cdef class _Schema:
cpdef as_enum(self): cpdef as_enum(self):
return _EnumSchema()._init(self.thisptr.asEnum()) return _EnumSchema()._init(self.thisptr.asEnum())
cpdef get_dependency(self, id):
'.. warning:: This method is deprecated and will be removed in the 0.6 release. You can access the fields directly from the schema now, so this method is superfluous and deprecated upstream'
_warnings.warn('This method is deprecated and will be removed in the 0.6 release. You can access the fields directly from the schema now, so this method is superfluous and deprecated upstream', UserWarning)
return _Schema()._init(self.thisptr.getDependency(id))
cpdef get_proto(self): cpdef get_proto(self):
return _NodeReader().init(self.thisptr.getProto()) return _NodeReader().init(self.thisptr.getProto())
@@ -2676,11 +2570,6 @@ cdef class _StructSchema:
def __get__(self): def __get__(self):
return _DynamicStructReader()._init(self.thisptr.getProto(), self) return _DynamicStructReader()._init(self.thisptr.getProto(), self)
cpdef get_dependency(self, id):
'.. warning:: This method is deprecated and will be removed in the 0.6 release. You can access the fields directly from the schema now, so this method is superfluous and deprecated upstream'
_warnings.warn('This method is deprecated and will be removed in the 0.6 release. You can access the fields directly from the schema now, so this method is superfluous and deprecated upstream', UserWarning)
return _Schema()._init(self.thisptr.getDependency(id))
def __richcmp__(_StructSchema self, _StructSchema other, mode): def __richcmp__(_StructSchema self, _StructSchema other, mode):
if mode == 2: if mode == 2:
return self.thisptr == other.thisptr return self.thisptr == other.thisptr
@@ -2814,11 +2703,6 @@ cdef class _InterfaceSchema:
def __get__(self): def __get__(self):
return _DynamicStructReader()._init(self.thisptr.getProto(), self) return _DynamicStructReader()._init(self.thisptr.getProto(), self)
cpdef get_dependency(self, id):
'.. warning:: This method is deprecated and will be removed in the 0.6 release. You can access the fields directly from the schema now, so this method is superfluous and deprecated upstream'
_warnings.warn('This method is deprecated and will be removed in the 0.6 release. You can access the fields directly from the schema now, so this method is superfluous and deprecated upstream', UserWarning)
return _Schema()._init(self.thisptr.getDependency(id))
def __repr__(self): def __repr__(self):
return '<schema for %s>' % self.node.displayName return '<schema for %s>' % self.node.displayName
@@ -2991,20 +2875,13 @@ cdef _new_message(self, kwargs, num_first_segment_words):
msg.from_dict(kwargs) msg.from_dict(kwargs)
return msg return msg
class _RestorerImpl(object):
pass
class _StructModuleWhich(object): class _StructModuleWhich(object):
pass pass
class _StructModule(object): class _StructModule(object):
def __init__(self, schema, name): def __init__(self, schema, name):
def _restore(self, obj):
return self.restore(obj.as_struct(self.schema))
self.schema = schema self.schema = schema
self.Restorer = type(name + '.Restorer', (_RestorerImpl,), {'schema':schema, '_restore':_restore})
# Add enums for union fields # Add enums for union fields
for field, raw_field in zip(schema.node.struct.fields, schema.fields_list): for field, raw_field in zip(schema.node.struct.fields, schema.fields_list):
if field.which() == 'group': if field.which() == 'group':

View File

@@ -10,7 +10,22 @@ examples_dir = os.path.join(os.path.dirname(__file__), '..', 'examples')
def run_subprocesses(address, server, client): def run_subprocesses(address, server, client):
server = subprocess.Popen([os.path.join(examples_dir, server), address]) server = subprocess.Popen([os.path.join(examples_dir, server), address])
time.sleep(1) # Give the server some small amount of time to start listening retries = 30
addr, port = address.split(':')
while True:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((addr, int(port)))
if result == 0:
break
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
result = sock.connect_ex((addr, int(port)))
if result == 0:
break
# Give the server some small amount of time to start listening
time.sleep(0.1)
retries -= 1
if retries == 0:
assert False, "Timed out waiting for server to start"
client = subprocess.Popen([os.path.join(examples_dir, client), address]) client = subprocess.Popen([os.path.join(examples_dir, client), address])
ret = client.wait() ret = client.wait()

View File

@@ -1,3 +1,7 @@
'''
rpc test
'''
import pytest import pytest
import capnp import capnp
import socket import socket
@@ -7,103 +11,28 @@ import test_capability_capnp
class Server(test_capability_capnp.TestInterface.Server): class Server(test_capability_capnp.TestInterface.Server):
def __init__(self, val=1): def __init__(self, val=100):
self.val = val self.val = val
def foo(self, i, j, **kwargs): def foo(self, i, j, **kwargs):
return str(i * 5 + self.val) return str(i * 5 + self.val)
def restore_func(ref_id):
return Server(100)
class SimpleRestorer(test_capability_capnp.TestSturdyRefObjectId.Restorer):
def restore(self, ref_id):
assert ref_id.tag == 'testInterface'
return Server(100)
def test_simple_rpc():
read, write = socket.socketpair(socket.AF_UNIX)
restorer = SimpleRestorer()
_ = capnp.TwoPartyServer(write, restorer)
client = capnp.TwoPartyClient(read)
ref = test_capability_capnp.TestSturdyRefObjectId.new_message(tag='testInterface')
cap = client.restore(ref)
cap = cap.cast_as(test_capability_capnp.TestInterface)
remote = cap.foo(i=5)
response = remote.wait()
assert response.x == '125'
def test_simple_rpc_with_options(): def test_simple_rpc_with_options():
read, write = socket.socketpair(socket.AF_UNIX) read, write = socket.socketpair(socket.AF_UNIX)
restorer = SimpleRestorer() _ = capnp.TwoPartyServer(write, bootstrap=Server())
_ = capnp.TwoPartyServer(write, restorer)
# This traversal limit is too low to receive the response in, so we expect # This traversal limit is too low to receive the response in, so we expect
# an exception during the call. # an exception during the call.
client = capnp.TwoPartyClient(read, traversal_limit_in_words=1) client = capnp.TwoPartyClient(read, traversal_limit_in_words=1)
ref = test_capability_capnp.TestSturdyRefObjectId.new_message(tag='testInterface')
with pytest.raises(capnp.KjException): with pytest.raises(capnp.KjException):
cap = client.restore(ref) cap = client.bootstrap().cast_as(test_capability_capnp.TestInterface)
cap = cap.cast_as(test_capability_capnp.TestInterface)
remote = cap.foo(i=5) remote = cap.foo(i=5)
_ = remote.wait() _ = remote.wait()
def test_simple_rpc_restore_func():
read, write = socket.socketpair(socket.AF_UNIX)
_ = capnp.TwoPartyServer(write, restore_func)
client = capnp.TwoPartyClient(read)
ref = test_capability_capnp.TestSturdyRefObjectId.new_message(tag='testInterface')
cap = client.restore(ref)
cap = cap.cast_as(test_capability_capnp.TestInterface)
remote = cap.foo(i=5)
response = remote.wait()
assert response.x == '125'
def text_restore_func(objectId):
text = objectId.as_text()
assert text == 'testInterface'
return Server(100)
def test_ez_rpc():
read, write = socket.socketpair(socket.AF_UNIX)
_ = capnp.TwoPartyServer(write, text_restore_func)
client = capnp.TwoPartyClient(read)
cap = client.ez_restore('testInterface')
cap = cap.cast_as(test_capability_capnp.TestInterface)
remote = cap.foo(i=5)
response = remote.wait()
assert response.x == '125'
cap = client.restore(test_capability_capnp.TestSturdyRefObjectId.new_message())
cap = cap.cast_as(test_capability_capnp.TestInterface)
remote = cap.foo(i=5)
with pytest.raises(capnp.KjException):
response = remote.wait()
def test_simple_rpc_bootstrap(): def test_simple_rpc_bootstrap():
read, write = socket.socketpair(socket.AF_UNIX) read, write = socket.socketpair(socket.AF_UNIX)

View File

@@ -23,7 +23,35 @@ def test_calculator():
def run_subprocesses(address): def run_subprocesses(address):
server = subprocess.Popen([examples_dir + '/calculator_server.py', address]) server = subprocess.Popen([examples_dir + '/calculator_server.py', address])
time.sleep(2) # Give the server some small amount of time to start listening retries = 30
if 'unix' in address:
addr = address.split(':')[1]
while True:
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
result = sock.connect_ex(addr)
if result == 0:
break
# Give the server some small amount of time to start listening
time.sleep(0.1)
retries -= 1
if retries == 0:
assert False, "Timed out waiting for server to start"
else:
addr, port = address.split(':')
while True:
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
result = sock.connect_ex((addr, int(port)))
if result == 0:
break
sock = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
result = sock.connect_ex((addr, int(port)))
if result == 0:
break
# Give the server some small amount of time to start listening
time.sleep(0.1)
retries -= 1
if retries == 0:
assert False, "Timed out waiting for server to start"
client = subprocess.Popen([examples_dir + '/calculator_client.py', address]) client = subprocess.Popen([examples_dir + '/calculator_client.py', address])
ret = client.wait() ret = client.wait()

View File

@@ -44,7 +44,7 @@ class Server(test_capability_capnp.TestInterface.Server):
''' '''
Server Server
''' '''
def __init__(self, val=1): def __init__(self, val=100):
self.val = val self.val = val
def foo(self, i, j, **kwargs): def foo(self, i, j, **kwargs):
@@ -54,19 +54,6 @@ class Server(test_capability_capnp.TestInterface.Server):
return str(i * 5 + self.val) return str(i * 5 + self.val)
class SimpleRestorer(test_capability_capnp.TestSturdyRefObjectId.Restorer):
'''
SimpleRestorer
'''
def restore(self, ref_id):
'''
Restore
'''
assert ref_id.tag == 'testInterface'
return Server(100)
@pytest.mark.skipif( @pytest.mark.skipif(
platform.python_implementation() == 'PyPy', platform.python_implementation() == 'PyPy',
reason="pycapnp's GIL handling isn't working properly at the moment for PyPy" reason="pycapnp's GIL handling isn't working properly at the moment for PyPy"
@@ -81,8 +68,7 @@ def test_using_threads():
read, write = socket.socketpair(socket.AF_UNIX) read, write = socket.socketpair(socket.AF_UNIX)
def run_server(): def run_server():
restorer = SimpleRestorer() _ = capnp.TwoPartyServer(write, bootstrap=Server())
_ = capnp.TwoPartyServer(write, restorer)
capnp.wait_forever() capnp.wait_forever()
server_thread = threading.Thread(target=run_server) server_thread = threading.Thread(target=run_server)
@@ -90,10 +76,7 @@ def test_using_threads():
server_thread.start() server_thread.start()
client = capnp.TwoPartyClient(read) client = capnp.TwoPartyClient(read)
cap = client.bootstrap().cast_as(test_capability_capnp.TestInterface)
ref = test_capability_capnp.TestSturdyRefObjectId.new_message(tag='testInterface')
cap = client.restore(ref)
cap = cap.cast_as(test_capability_capnp.TestInterface)
remote = cap.foo(i=5) remote = cap.foo(i=5)
response = remote.wait() response = remote.wait()