pycapnp icon indicating copy to clipboard operation
pycapnp copied to clipboard

Cannot proxy requests?

Open Zentren opened this issue 3 years ago • 0 comments

Is it not possible to proxy-chain requests returning (at least) struct responses?

i.e. client <=> proxy.rpc() <=> server.rpc()

Please see attached test code to better understand issue and reproduce. Commented-out lines from line 22 can be uncommented separately to investigate (not-so-different) outcomes. Either an exception is raised, or default values for fields are returned.

Test code

test.py

from unittest import result
import capnp
import socket

import test_capnp


class Test(test_capnp.Test.Server):

    def getResult(self, **kwargs):
        return test_capnp.Result.new_message(value=1)


class TestProxy(test_capnp.Test.Server):

    def __init__(self, test):
        self._test = test

    def getResult(self, **kwargs):
        return self._test.getResult()  # remote exception: <class 'AttributeError'>:'NoneType' object has no attribute 'type'

        # return self._test.getResult().result  # remote exception: <class 'AttributeError'>:'NoneType' object has no attribute 'type'

        # return self._test.getResult().then(lambda response: {"value": 1})
        
        # return self._test.getResult().then(
        #     lambda _: test_capnp.Result.new_message(value=1),
        #     error_func=lambda error: print(error),
        # )

        # return self._test.getResult().then(
        #     lambda response: self._copy_response_result(response),
        #     error_func=lambda error: print(error),
        # )

        # return self._test.getResult().then(
        #     lambda response: self._copy_response_result_as_builder(response),
        #     error_func=lambda error: print(error),
        # )

        # return self._test.getResult().then(
        #     lambda response: self._reuse_response(response),
        #     error_func=lambda error: print(error),
        # )

    def _reuse_response(self, response):
        print("Server result value: " + str(response.result.value))
        return response

    def _copy_response_result(self, response):
        print("Server result value: " + str(response.result.value))
        return test_capnp.Result.new_message(value=response.result.value)

    def _copy_response_result_as_builder(self, response):
        print("Server result value: " + str(response.result.value))
        return response.result.as_builder()


def test():
    principal_server_sock, principal_client_sock = socket.socketpair(socket.AF_UNIX)

    principal_server = capnp.TwoPartyServer(principal_server_sock, bootstrap=Test())
    principal_client = capnp.TwoPartyClient(principal_client_sock)

    proxy_server_sock, proxy_client_sock = socket.socketpair(socket.AF_UNIX)

    proxy = TestProxy(principal_client.bootstrap().cast_as(test_capnp.Test))
    proxy_server = capnp.TwoPartyServer(proxy_server_sock, bootstrap=proxy)
    proxy_client = capnp.TwoPartyClient(proxy_client_sock)

    test_client = proxy_client.bootstrap().cast_as(test_capnp.Test)
    
    result = test_client.getResult().wait().result

    print("Proxy result: " + str(result))
    assert result.value == 1


if __name__ == "__main__":
    test()

test.capnp

@0xc5358bd118c9ee3a;

struct Result {
    value @0 :Int32;
}

interface Test {
    getResult @0 () -> (result :Result);
}

Zentren avatar Jul 12 '22 11:07 Zentren