Collaboration Tutorial: Difference between revisions
(Link to Shared Sugar Activities) |
(Add translation template.) |
||
(10 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
{{Translations}} |
|||
⚫ | |||
{{Developers}} |
|||
⚫ | |||
See [[Collaboration Central]] for all things relating to activity collaboration. |
|||
⚫ | Collaboration is implemented with Telepathy, a D-Bus framework for Instant Messaging protocols. The [[Presence Service]] provides functionality to Sugar to track shared Activities and Buddies, and talks to Telepathy connection managers for XMPP via a Jabber server (telepathy-gabble), and Link Local XMPP (telepathy-salut). |
||
== Introduction == |
|||
⚫ | Collaboration is implemented with [[Telepathy]], a D-Bus framework for Instant Messaging protocols. The [[Presence Service]] provides functionality to Sugar to track shared Activities and Buddies (and show them on the Neighborhood View), and talks to Telepathy connection managers for XMPP via a Jabber server ([[Telepathy Gabble|telepathy-gabble]]), and Link Local XMPP ([[Telepathy Salut|telepathy-salut]]). |
||
XMPP is used to provide presence information about Buddies (other XOs you can collaborate with). The mesh view is like an instant messenger buddy list, represented in a more graphical way. |
XMPP is used to provide presence information about Buddies (other XOs you can collaborate with). The mesh view is like an instant messenger buddy list, represented in a more graphical way. |
||
Not all the Buddies you see are on the same network as you. In particular, any of them could be behind a NAT firewall, and so you cannot simply open a TCP/IP socket to them to exchange data. |
Not all the Buddies you see are on the same network as you. In particular, any of them could be behind a NAT firewall, and so you cannot simply open a TCP/IP socket to them to exchange data. Furthermore, while it is not yet implemented, Bitfrost's [[OLPC Bitfrost#P_NET: network policy protection|P_NET]] protection will restrict activities' use of networking, but not apply to collaboration via Telepathy.[http://lists.laptop.org/pipermail/devel/2008-June/015291.html] |
||
XMPP via the Jabber server on the school server allows you to exchange data with all the Buddies you can see, whether or not they are directly reachable from your XO. |
XMPP via the Jabber server on the school server allows you to exchange data with all the Buddies you can see, whether or not they are directly reachable from your XO. |
||
== |
=== Shared Activities === |
||
A shared activity is implemented using an XMPP MUC (multi user chat room). Buddies that are in the room, are in the shared activity. |
A shared activity is implemented using an XMPP MUC (multi user chat room). Buddies that are in the room, are in the shared activity. |
||
Presence Service provides each shared activity with a Telepathy Text Channel by default. This text channel is a connection to the XMPP chat room, but is not useful for data sharing directly. You can see an example of this Text Channel in direct use in the [[Chat]] activity. In future, Sugar will provide "overlay chat" to activities, allowing you to do text chat with the participants of a shared activity. |
|||
On top of this Text Channel, |
On top of this Text Channel, PS provides a Tubes channel to exchange data with the other participants via Tubes. |
||
== Tubes |
=== Tubes === |
||
There are two types of Tubes at present: D-Bus Tubes and Stream Tubes. |
There are two types of [[Activity sharing#Tubes]] at present: D-Bus Tubes and Stream Tubes. |
||
D- |
D-Bus Tubes provide D-Bus functionality to signal and call methods on everyone in the room. |
||
Stream Tubes wrap TCP/IP sockets and are more suited to streaming data between two participants. |
Stream Tubes wrap TCP/IP sockets and are more suited to streaming data between two participants. |
||
== D-Bus Tubes == |
=== D-Bus Tubes === |
||
See the [http://dbus.freedesktop.org/doc/dbus-tutorial.html D-Bus tutorial] and the [http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html dbus-python tutorial]. |
See the [http://dbus.freedesktop.org/doc/dbus-tutorial.html D-Bus tutorial] and the [http://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html dbus-python tutorial]. |
||
Line 37: | Line 43: | ||
''More to come here...'' |
''More to come here...'' |
||
=== Bus names, handles, Buddy objects === |
==== Bus names, handles, Buddy objects ==== |
||
Signals and Methods use bus names to identify senders and recipients. Telepathy uses handles to identify participants. Sugar uses Buddy objects. |
Signals and Methods use bus names to identify senders and recipients. Telepathy uses handles to identify participants. Sugar uses Buddy objects. |
||
Line 45: | Line 51: | ||
''More to come here...'' |
''More to come here...'' |
||
=== |
=== Stream Tubes === |
||
[ |
See the [[Read]] activity's code for an example. It's in git://dev.laptop.org/projects/read-activity and is built by default in sugar-jhbuild. |
||
⚫ | |||
== Example Activity: HelloMesh == |
|||
[[HelloMesh]] is a demo activity with sample code using a D-Bus Tube. The code is in ''git://dev.laptop.org/projects/hellomesh'' and can be built in sugar-jhbuild with ''./sugar-jhbuild buildone hellomesh'' |
|||
First, let's look at HelloMesh's D-Bus Tubes API. There |
First, let's look at HelloMesh's D-Bus Tubes API. There are two '''signals''' and one '''method''': |
||
@signal(dbus_interface=IFACE, signature='') |
@signal(dbus_interface=IFACE, signature='') |
||
Line 57: | Line 69: | ||
@method(dbus_interface=IFACE, in_signature='s', out_signature='') |
@method(dbus_interface=IFACE, in_signature='s', out_signature='') |
||
def World(self, |
def World(self, text): |
||
"""To be called on the incoming XO after they Hello.""" |
"""To be called on the incoming XO after they Hello.""" |
||
if not self. |
if not self.text: |
||
self._logger.debug('Somebody |
self._logger.debug('Somebody called World and sent me %s', |
||
text) |
|||
self._alert('World', 'Received %s' % text) |
|||
self.text = text |
|||
self.text_received_cb(text) |
|||
# now I can World others |
# now I can World others |
||
self.add_hello_handler() |
self.add_hello_handler() |
||
else: |
else: |
||
self._logger.debug("I've already been welcomed, doing nothing") |
self._logger.debug("I've already been welcomed, doing nothing") |
||
@signal(dbus_interface=IFACE, signature='s') |
|||
def SendText(self, text): |
|||
"""Send some text to all participants.""" |
|||
self.text = text |
|||
self._logger.debug('Sent text: %s', text) |
|||
self._alert('SendText', 'Sent %s' % text) |
|||
When a new participant joins the shared activity, it sends the Hello signal. This goes to all existing participants. The Hello signal has an empty signature, since no actual parameters are being sent. |
When a new participant joins the shared activity, it sends the Hello signal. This goes to all existing participants. The Hello signal has an empty signature, since no actual parameters are being sent. |
||
When an (existing) participant receives the Hello signal, it calls the World method of the signal's sender. The World method takes a string parameter ( |
When an (existing) participant receives the Hello signal, it calls the World method of the signal's sender. The World method takes a string parameter (text) represented by <pre>in_signature='s'</pre>It doesn't return anything, hence <pre>out_signature=''</pre> |
||
Calling World when Hello is received is done in hello_cb: |
Calling World when Hello is received is done in hello_cb: |
||
Line 80: | Line 102: | ||
self._logger.debug('Newcomer %s has joined', sender) |
self._logger.debug('Newcomer %s has joined', sender) |
||
self._logger.debug('Welcoming newcomer and sending them the game state') |
self._logger.debug('Welcoming newcomer and sending them the game state') |
||
⚫ | |||
game_state = str(time.time()) # Something to send for demo |
|||
⚫ | |||
dbus_interface=IFACE) |
dbus_interface=IFACE) |
||
Line 93: | Line 114: | ||
self._logger.debug('Adding hello handler.') |
self._logger.debug('Adding hello handler.') |
||
self.tube.add_signal_receiver(self.hello_cb, 'Hello', IFACE, |
self.tube.add_signal_receiver(self.hello_cb, 'Hello', IFACE, |
||
path=PATH, sender_keyword='sender') |
|||
self.tube.add_signal_receiver(self.sendtext_cb, 'SendText', IFACE, |
|||
path=PATH, sender_keyword='sender') |
path=PATH, sender_keyword='sender') |
||
You can see this called in the World method above, because in this example once we have had our World method called by an existing participant, we can then respond to somebody else's Hello signal. |
You can see this called in the World method above, because in this example once we have had our World method called by an existing participant, we can then respond to somebody else's Hello signal. |
||
This also adds a signal receiver for the SendText signal, defined above, which sends the text from the user interface. |
|||
⚫ | |||
== |
==See Also == |
||
[[Sugar_Almanac#Package:_sugar.presence]] |
|||
[[Category:Collaboration]] |
|||
See the [[Read]] activity's code for an example. It's in git://dev.laptop.org/projects/read-activity and is built by default in sugar-jhbuild. |
|||
[[Category:Telepathy]] |
|||
''More to come here...'' |
Latest revision as of 17:15, 28 June 2011
This tutorial focuses on activity sharing. Read Activity sharing for an overview of the concepts. See also Presence Service and Tubes.
See Collaboration Central for all things relating to activity collaboration.
Introduction
Collaboration is implemented with Telepathy, a D-Bus framework for Instant Messaging protocols. The Presence Service provides functionality to Sugar to track shared Activities and Buddies (and show them on the Neighborhood View), and talks to Telepathy connection managers for XMPP via a Jabber server (telepathy-gabble), and Link Local XMPP (telepathy-salut).
XMPP is used to provide presence information about Buddies (other XOs you can collaborate with). The mesh view is like an instant messenger buddy list, represented in a more graphical way.
Not all the Buddies you see are on the same network as you. In particular, any of them could be behind a NAT firewall, and so you cannot simply open a TCP/IP socket to them to exchange data. Furthermore, while it is not yet implemented, Bitfrost's P_NET protection will restrict activities' use of networking, but not apply to collaboration via Telepathy.[1]
XMPP via the Jabber server on the school server allows you to exchange data with all the Buddies you can see, whether or not they are directly reachable from your XO.
A shared activity is implemented using an XMPP MUC (multi user chat room). Buddies that are in the room, are in the shared activity.
Presence Service provides each shared activity with a Telepathy Text Channel by default. This text channel is a connection to the XMPP chat room, but is not useful for data sharing directly. You can see an example of this Text Channel in direct use in the Chat activity. In future, Sugar will provide "overlay chat" to activities, allowing you to do text chat with the participants of a shared activity.
On top of this Text Channel, PS provides a Tubes channel to exchange data with the other participants via Tubes.
Tubes
There are two types of Activity sharing#Tubes at present: D-Bus Tubes and Stream Tubes.
D-Bus Tubes provide D-Bus functionality to signal and call methods on everyone in the room.
Stream Tubes wrap TCP/IP sockets and are more suited to streaming data between two participants.
D-Bus Tubes
See the D-Bus tutorial and the dbus-python tutorial.
D-Bus provides signals and methods:
- Signals are multicast - they are sent to all participants in the shared activity (including the sender). They send data and have no return value.
- Method calls are called on a single participant, and they do have a return value.
It is important to design your Activity's D-Bus Tubes API well, to support the functionality that your collaboration will need.
More to come here...
Bus names, handles, Buddy objects
Signals and Methods use bus names to identify senders and recipients. Telepathy uses handles to identify participants. Sugar uses Buddy objects.
The TubeConnection object can convert between bus names and handles - see tubeconn.py for details.
More to come here...
Stream Tubes
See the Read activity's code for an example. It's in git://dev.laptop.org/projects/read-activity and is built by default in sugar-jhbuild.
More to come here...
Example Activity: HelloMesh
HelloMesh is a demo activity with sample code using a D-Bus Tube. The code is in git://dev.laptop.org/projects/hellomesh and can be built in sugar-jhbuild with ./sugar-jhbuild buildone hellomesh
First, let's look at HelloMesh's D-Bus Tubes API. There are two signals and one method:
@signal(dbus_interface=IFACE, signature=) def Hello(self): """Say Hello to whoever else is in the tube.""" self._logger.debug('I said Hello.')
@method(dbus_interface=IFACE, in_signature='s', out_signature=) def World(self, text): """To be called on the incoming XO after they Hello.""" if not self.text: self._logger.debug('Somebody called World and sent me %s', text) self._alert('World', 'Received %s' % text) self.text = text self.text_received_cb(text) # now I can World others self.add_hello_handler() else: self._logger.debug("I've already been welcomed, doing nothing")
@signal(dbus_interface=IFACE, signature='s') def SendText(self, text): """Send some text to all participants.""" self.text = text self._logger.debug('Sent text: %s', text) self._alert('SendText', 'Sent %s' % text)
When a new participant joins the shared activity, it sends the Hello signal. This goes to all existing participants. The Hello signal has an empty signature, since no actual parameters are being sent.
When an (existing) participant receives the Hello signal, it calls the World method of the signal's sender. The World method takes a string parameter (text) represented by
in_signature='s'
It doesn't return anything, hence
out_signature=''
Calling World when Hello is received is done in hello_cb:
def hello_cb(self, sender=None): """Somebody Helloed me. World them.""" if sender == self.tube.get_unique_name(): # sender is my bus name, so ignore my own signal return self._logger.debug('Newcomer %s has joined', sender) self._logger.debug('Welcoming newcomer and sending them the game state') self.tube.get_object(sender, PATH).World(self.text, dbus_interface=IFACE)
Note that signals go to all participants, including yourself - the above code shows how to ignore your own signals.
sender is a bus (as in D-Bus) name, like :2.OWI0MTk2MzNAdmFpbwAA. Signals and Methods use these to identify senders and recipients.
In order to receive the Hello signal, we need to add a signal receiver:
def add_hello_handler(self): self._logger.debug('Adding hello handler.') self.tube.add_signal_receiver(self.hello_cb, 'Hello', IFACE, path=PATH, sender_keyword='sender') self.tube.add_signal_receiver(self.sendtext_cb, 'SendText', IFACE, path=PATH, sender_keyword='sender')
You can see this called in the World method above, because in this example once we have had our World method called by an existing participant, we can then respond to somebody else's Hello signal.
This also adds a signal receiver for the SendText signal, defined above, which sends the text from the user interface.