Events and Callbacks¶
Events¶
Methods of custom classes inheriting from LocalHERO
can be marked as an event using the @event
decorator.
Doing so replaces the method with a heros.event.LocalEventHandler
and implies two things:
The method now supports callbacks (see Callbacks) which are executed using the return value of the decorated method.
The return value of the decorated method is published to a unique endpoint within the realm of the zenoh network.
In the remote representation of the object - the RemoteHERO
- the event is represented as a heros.event.RemoteEventHandler
.
This the remote event supports callbacks which are executed using the payload received via the local event endpoint in the zenoh network.
Note
The remote representation of an event is not callable itself.
Callbacks¶
The syntax for using callbacks is regardless wether the we deal with a local or a remote event.
Connecting or disconnecting a callable func
as a callback to an event my_event
is performed via my_event.connect(func)
and my_event.disconnect(func)
, respectively.
Calling my_event.get_callbacks()
returns a list of callbacks.
Callbacks of events can be categorized into four cases differentiated by the execution context of the event (LocalEventHandler
or RemoteEventHandler
) and the type of the callable.
Consider the event my_event
of alice
:
class Alice(LocalHERO):
@event
def my_event(self, value):
return do_sth(value)
# instantiate a local alice
alice = Alice()
Additionally, consider the three execution contexts (i.e. three python interpreters on three hosts):
ALICE
where theLocalHERO
of a classAlice
is instantiated.
BOB
where theLocalHERO
of a classBob
is instantiated.
EVE
where only remote representations (RemoteHERO
) ofalice
andbob
are present.
For a full example, also consider examples/connect_event_callbacks.py
.
Case A: Local object, local callback¶
# execution context ALICE
alice.my_event.connect(print)
Whenever my_event
returns, the function print
is called in the execution context ALICE
.
Therefore, the callback can be understood as print(alice.my_event(value))
.
Case B: Local object, remote callback¶
# execution context ALICE
# get a remote representation of bob
remote_bob = RemoteHERO("bob")
alice.my_event.connect(remote_bob.the_builder)
Whenever my_event
returns, the method the_builder
of the remote representation of bob
is called in the execution context ALICE
.
Therefore, the callback can be understood as remote_bob.the_builder(alice.my_event(value))
.
Case C: Remote object, local callback¶
# execution context EVE
# get a remote representation of alice
remote_alice = RemoteHERO("alice")
remote_alice.my_event.connect(print)
Whenever my_event
of alice
(the LocalHERO
) returns, the function print
is called in the execution context of EVE
.
In this case, the RemoteEventHandler
representation of the my_event
(remote_alice.my_event
) calls print
once it receives the return value of alice.my_event
via the zenoh network.
Case D: Remote object, remote callback¶
# execution context EVE
# get remote representations of alice and bob
remote_alice = RemoteHERO("alice")
remote_bob = RemoteHERO("bob")
remote_alice.my_event.connect(remote_bob.the_builder)
Connecting the remote callable remote_bob.the_builder
to the remote representation remote_alice.my_event
in the context of EVE
leads to a special behavior.
The callable remote_bob.the_builder
is automatically attached as a remote callback to alice
(the LocalHERO
) similar to case B.
This way, calling remote_bob.the_builder
upon return of alice.my_event
is handled as a direct P2P connection between the contexts ALICE
and BOB
.