diff --git a/capnp/rpcHelper.h b/capnp/rpcHelper.h new file mode 100644 index 0000000..1dc18ea --- /dev/null +++ b/capnp/rpcHelper.h @@ -0,0 +1,42 @@ +#pragma once + +#include "capnp/dynamic.h" +#include "capnp/rpc-twoparty.h" +#include "Python.h" +#include "capabilityHelper.h" + +extern "C" { + capnp::Capability::Client * call_py_restorer(PyObject *, capnp::DynamicStruct::Reader &); +} + +class PyRestorer final: public capnp::SturdyRefRestorer { +public: + PyRestorer(PyObject * _py_restorer, capnp::StructSchema& _schema): py_restorer(_py_restorer), schema(_schema) { + // 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::ObjectPointer::Reader objectId) override { + auto reader = objectId.getAs(schema); + capnp::Capability::Client * ret = call_py_restorer(py_restorer, reader); + check_py_error(); + capnp::Capability::Client stack_ret(*ret); + delete ret; + + return stack_ret; + } + +private: + PyObject * py_restorer; + capnp::StructSchema schema; +}; + +capnp::Capability::Client restoreHelper(capnp::RpcSystem& client, capnp::MessageBuilder & objectId) { capnp::MallocMessageBuilder hostIdMessage(8); + auto hostId = hostIdMessage.initRoot(); + hostId.setSide(capnp::rpc::twoparty::Side::SERVER); + return client.restore(hostId, objectId.getRoot()); +} diff --git a/test/test_rpc.py b/test/test_rpc.py new file mode 100644 index 0000000..c920ff5 --- /dev/null +++ b/test/test_rpc.py @@ -0,0 +1,36 @@ +import pytest +import capnp +import os + +this_dir = os.path.dirname(__file__) + +@pytest.fixture +def capability(): + return capnp.load(os.path.join(this_dir, 'test_capability.capnp')) + +class Server: + def __init__(self, val=1): + self.val = val + + def foo(self, context): + context.results.x = str(context.params.i * 5 + self.val) + +def test_simple_rpc(capability): + def _restore(ref_id): + return capability.TestInterface.new_server(Server(100)) + + loop = capnp.EventLoop() + pipe = capnp.TwoWayPipe() + + restorer = capnp.Restorer(capability.TestSturdyRefObjectId, _restore) + server = capnp.RpcServer(loop, restorer, pipe) + client = capnp.RpcClient(loop, pipe) + + ref = capability.TestSturdyRefObjectId.new_message() + cap = client.restore(ref.as_reader()) + cap = cap.cast_as(capability.TestInterface) + + remote = cap.foo(i=5) + response = loop.wait_remote(remote) + + assert response.x == '125'