Hi Joe,

Take a look at the doc comments for thisCap():

  inline Capability::Client thisCap();
  // Get a capability pointing to this object, much like the `this` keyword.
  //
  // The effect of this method is undefined if:
  // - No capability client has been created pointing to this object. (This
is always the case in
  //   the server's constructor.)
  // - The capability client pointing at this object has been destroyed.
(This is always the case
  //   in the server's destructor.)
  // - Multiple capability clients have been created around the same server
(possible if the server
  //   is refcounted, which is not recommended since the client itself
provides refcounting).

Your code is hitting the first bullet point -- you're trying to call
thisCap() before any capability client has been created.

What you really want to do here is take advantage of the fact that
capability clients are copyable using reference counting. You can create a
client, and then keep a copy for yourself, like so:

    auto server = kj::heap<MyTypeImpl>(...);
    auto& serverRef = *server;
    MyType::Client capability = kj::mv(server);

    // Send a ref to the client.
    context.getResults().setApp(capability);

    // Also keep one for ourself, along with a reference to the
implementation
    myServers.add(ClientRefPair { client, serverRef });

By keeping a `Client` that points to your server object, you ensure that
the refcount remains non-zero so the object stays alive. As shown above,
you can separately keep a reference or pointer to the underlying server
object if you need to be able to access it's C++ interface directly.

Note that your server's destructor is only called after all references --
yours, and remote references -- are dropped. If you need to force your
server object to be destroyed at a specific time, then you'll need to do
one of the following:

- Use a layer of indirection where your server object wraps another object
that can be nulled out later, such that all the RPC methods start throwing
exceptions once nulled.
- Wrap the Client object in a membrane (capnp/membrane.h) which you later
revoke.

-Kenton

On Thu, Apr 18, 2019 at 10:00 PM Joe Ludwig <programmer....@gmail.com>
wrote:

> I have a really simple RPC protocol:
> interface AvServer
> {
>  createApp @0 ( name: Text ) -> ( app: AvApp );
> }
>
>
> interface AvApp
> {
>  name @0 () -> ( name: Text );
>
>
>  destroy @1 ();
> }
>
>
> I implement that on the server with two concrete classes:
>
>  class AvServerImpl final : public AvServer::Server
>  class CAardvarkApp final: public AvApp::Server
>
>
>
> And then when the client calls createApp I want to create an AvApp, return
> a reference to it, and keep ownership of the app itself in some
> datastructure on the server:
>
>  ::kj::Promise<void> AvServerImpl::createApp( CreateAppContext context )
>  {
>  // "works"
>  context.getResults().setApp( kj::heap<CAardvarkApp>( context.getParams().
> getName() ) );
>
>
>  // crashes because "thisHook" is null
>  auto pApp = kj::heap<CAardvarkApp>( context.getParams().getName() );
>  context.getResults().setApp( pApp->GetClient() ); // GetClient() is just
> a call to thisCap()
>  m_listApps.push_back( std::move( pApp ) );
>
>
>  return kj::READY_NOW;
>  }
>
>
> The first approach there works, but the AvServerImpl class doesn't keep
> any kind of record of the new CAardvarkApp object, so it won't be able to
> do anything with the app outside of a call from this one particular client.
>
> What I'm attempting to do in the second approach is create an object on
> the heap and set it in the results, but keep ownership of it in the list. I
> don't get that far, though, because thisCap crashes because thisHook
> returns nullptr.
>
> I think I must be missing something really fundamental about how all this
> is supposed to work. Am I required to create a unique foo::Server object
> for each incoming call that refers to a single logical object? If I have to
> pass ownership to the results in order to return values, it seems like
> something along that line will be called for. That doesn't sound right,
> though, since I'd have to manage an unbounded number of those objects as
> requests come in from different clients.
>
> Help? :)
>
>
> Joe
>
> --
> You received this message because you are subscribed to the Google Groups
> "Cap'n Proto" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to capnproto+unsubscr...@googlegroups.com.
> Visit this group at https://groups.google.com/group/capnproto.
>

-- 
You received this message because you are subscribed to the Google Groups 
"Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to capnproto+unsubscr...@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.

Reply via email to