On Wed, Feb 22, 2017 at 12:22 AM, Johannes Zeppenfeld <[email protected]>
wrote:
> Thanks for the tip! I knew I couldn't have been the first person to need
> something like this, and installing from git is fine.
>
> However... getLocalServer returns a promise, which again makes it
> impossible to call the Callable functions from within the process method.
> Is there a way to get the server object directly? I don't see any way for
> the Client object to be a promise at this point...
>
Any `Client` object could in fact be backed by a promise! There are a lot
of different situations where Cap'n Proto lets you make calls to a
capability before it is actually known where the capability points -- these
calls will be queued somewhere until the capability "settles" (when the
promise resolves). The best-known case of this is, of course, promise
pipelining, where you can make calls to capabilities that you expect will
be returned by some other call that is currently in progress. But you can
also create a promise capability by simply casting a kj::Promise<T::Client>
to T::Client -- this creates a capability which will queue calls locally
until the promise resolves, then deliver them. You could then send this
promise-capability to a remote machine, which could then start sending its
own calls back to you to add to the queue. You might later resolve the
promise to a capability that is hosted on that same remote machine. Cap'n
Proto will then inform the remote machine that the capability it received
previously now points to an object local to that machine -- at which point
the remote machine should be able to unwrap it using CapabilityServerSet!
Because of all this, there's no way for your application to know for sure
if a capability is settled yet, but CapabilityServerSet obviously can only
unwrap a capability once it is settled. So, it must return a promise.
Otherwise I suppose I'd have to split the process method into two parts,
> first starting retrieval of all of the local server objects, joining the
> returned promises and then processing them in a second step. This becomes
> difficult when dealing with heterogeneous server object types though, e.g.
> if there are Actions for Callable and another type, e.g., Executable. Is
> there something similar to joinPromises that works with heterogeneous types?
>
You can join promises in a sort of hacky way using chaining, like:
Promise<T> promise1 = ...;
Promise<U> promise2 = ...;
return promise1.then([promise2 = kj::mv(promise2)](T t) mutable {
return promise2.then([t = kj::mv(t)](U u) mutable {
return doSomething(t, u);
});
});
There's no downside to this except that it's ugly.
At some point I'd like to add support for joining heterogeneous promises
into Promise<Tuple<...>>. There's already a split() method that splits
Promise<Tuple<>> into Tuple<Promise<>>. I'd also like for
Promise<Tuple<...>>::then() to pass the tuple as multiple arguments to the
callback (not as a tuple).
-Kenton
>
> Thanks!
> Johannes
>
> On Tuesday, February 21, 2017 at 7:21:43 PM UTC+1, David Renshaw wrote:
>>
>> You can accomplish that with CapabilityServerSet, which was added in this
>> commit: https://github.com/sandstorm-io/capnproto/commit/8b8
>> f8a2fc25d69c8a43ee0ac987521c2c4d5108c .
>>
>> Unfortunately, there has not yet been a release that includes
>> CapabilityServerSet, so you would need to install Cap'n Proto from git to
>> make use of it.
>>
>> On Tue, Feb 21, 2017 at 1:06 PM, Johannes Zeppenfeld <[email protected]>
>> wrote:
>>
>>> Knowing that the answer to the question in the subject is probably
>>> "don't do that", I'm looking for a way to support database-like
>>> transactions (i.e., event-loop atomic operations) spanning multiple server
>>> objects.
>>>
>>> Here's a simplified schema to help explain the problem:
>>>
>>> # A transaction holds a list of actions that should be processed in a
>>> single
>>> # event-loop atomic operation.
>>> struct Transaction {
>>> actions @0 :List(Action);
>>>
>>> struct Action {
>>> union {
>>> nop @0 :Void;
>>> execute @1 :Callable;
>>> #doSomething @2 :AnotherType;
>>> #etc...
>>> }
>>> }
>>> }
>>>
>>> # A callable is a server-side object conveying the capability of calling
>>> # some server function as part of a transaction.
>>> interface Callable { }
>>>
>>> # Some other interface that serves callables (simplified example) and
>>> # processes transactions.
>>> interface Bootstrap {
>>> getCallable @0 (name :Text) -> (callable :Callable);
>>>
>>> process @1 (transaction :Transaction);
>>> }
>>>
>>> A client can obtain Callables from the server through e.g. the Bootstrap
>>> interface, and should then be able to pass that Callable as part of a
>>> Transaction back to the server. The Callable::Server implementation
>>> contains a std::function that should be called for any Callable that is
>>> executed as part of a transaction.
>>>
>>> Unfortunately (although it totally makes sense), the Transaction Reader
>>> available in the Bootstrap implementation's process method only provides a
>>> Callable::Client, without a possibility (as far as I can tell) of
>>> retrieving the associated Callable::Server object. Thus it is not possible
>>> to retrieve nor call the std::function object associated with the Callable.
>>>
>>> Adding a call method to the Callable interface would allow it to be
>>> called by the process method or directly by the client, but not (again as
>>> far as I can tell) in an event-loop atomic manner as part of a transaction.
>>>
>>> I hope that the scenario above is understandable. If not I'd be more
>>> than happy to elaborate on points that are not clear.
>>>
>>> Am I overlooking something that would allow somehow calling the
>>> std::function of a Callable implementation from within the process method?
>>> Does anyone have a different suggestion for achieving something like this?
>>>
>>> I would like to avoid implementing a custom capability system that
>>> replaces Callable with a struct containing an id. But perhaps it is the
>>> only way?
>>>
>>> Thanks!
>>> Johannes
>>>
>>> --
>>> 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 [email protected].
>>> 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 [email protected].
> 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 [email protected].
Visit this group at https://groups.google.com/group/capnproto.