Changes

Jump to navigation Jump to search
m
Line 1: Line 1: −
{{Sugar Almanac}}
+
{{Almanac}}
 
=== How do I setup a D-Bus Tube? ===
 
=== How do I setup a D-Bus Tube? ===
   −
Let's first look at what conceptually happens to make activity sharing work. The diagram below shows two instances of the same activity: the "Sharing Activity" and the "Joining Activity". The sharing activity is the activity that is initially run and shared with other buddies. The "Joining Activity" refers to other instances of the activity that are created once buddies decide to join an activity that has been shared. You can allow an activity to be shared (making it a sharing activity) by  [[Sugar.presence.presenceservice#How do I share an activity with other buddies in my neighborhood? | including the standard Sugar Activity Toolbar]].
+
Let's first look at what conceptually happens to make activity sharing work. The diagram below shows two instances of the same activity: the "Sharing Activity" and the "Joining Activity". The sharing activity is the activity that is initially run and shared with other buddies. The "Joining Activity" refers to other instances of the activity that are created once buddies decide to join an activity that has been shared. You can allow an activity to be shared (making it a sharing activity) by  [[Development Team/Almanac/Sugar.presence.presenceservice#How do I share an activity with other buddies in my neighborhood? | including the standard Sugar Activity Toolbar]].
    
[[Image:tube-setup.jpg | How Tubes are Setup]]
 
[[Image:tube-setup.jpg | How Tubes are Setup]]
Line 110: Line 110:  
     def _new_tube_cb(self, id, initiator, type, service, params, state):
 
     def _new_tube_cb(self, id, initiator, type, service, params, state):
 
          
 
          
         if (type == telepathy.TUBE_TYPE_DBUS and service == SERVICE):
+
         if type == telepathy.TUBE_TYPE_DBUS and service == SERVICE:
 
             if state == telepathy.TUBE_STATE_LOCAL_PENDING:
 
             if state == telepathy.TUBE_STATE_LOCAL_PENDING:
 
                 #Accept the new tube that has been created  
 
                 #Accept the new tube that has been created  
Line 262: Line 262:  
[[Image:stream-tube-in-annotate-activity.jpg | How annotate's stream tube will be used]]
 
[[Image:stream-tube-in-annotate-activity.jpg | How annotate's stream tube will be used]]
   −
Notice that the stream tube exists as a complement to the [http://en.wikipedia.org/wiki/Internet_socket socket architecture] used by Unix systems to facilitate internet communication.
+
Notice that the stream tube exists on top of the [http://en.wikipedia.org/wiki/Internet_socket socket architecture] used by Unix systems to facilitate internet communication.
    
==== Step 2: Define or identify the classes you will use to serve data and receive data through your stream tube. ====
 
==== Step 2: Define or identify the classes you will use to serve data and receive data through your stream tube. ====
Line 305: Line 305:     
==== Step 3: Coordinate sharing and joining in your activity using stream tubes and the client/server classes defined above. ====
 
==== Step 3: Coordinate sharing and joining in your activity using stream tubes and the client/server classes defined above. ====
 +
 +
On the sharing instance, the following must happen:
 +
* Once the activity has been shared by the user, the sharing instance should detect the "shared" signal and setup for sharing.
 +
* To setup for sharing, the sharing instance needs to instantiate a new server (in Annotate, this is an AnnotateHTTPServer) that will deliver content to any client activities.
 +
* The newly instantiated server should listen on a given port and that port should be connected to a new stream tube. The stream tube can be created by calling the iface.OfferStreamTube() method.
 +
 +
 +
For the joining activity, it must coordinate several steps once the "joined" signal has been detected:
 +
* The joining activity needs to wait for a valid stream tube that is provided under the service ANNOTATE_STREAM_SERVICE.
 +
* When such a tube is available, the joining activity should specify the path where the downloaded data will be saved.
 +
* Create a listening client on the address and port associated with the stream tube that has been found. In our case, we create a sugar.network.GlibURLDownloader instance that will manage downloading from the stream tube.
 +
 
<pre>
 
<pre>
 
ANNOTATE_STREAM_SERVICE = 'annotate-activity-http'
 
ANNOTATE_STREAM_SERVICE = 'annotate-activity-http'
Line 314: Line 326:     
         ...
 
         ...
      
         #Joining activity needs to know which stream tubes are available for downloading  
 
         #Joining activity needs to know which stream tubes are available for downloading  
Line 372: Line 383:  
     # instance
 
     # instance
 
     def _joined_cb(self, also_self):
 
     def _joined_cb(self, also_self):
        self._update_chat_text('SYSTEM', '_joined_cb()')
   
         self.watch_for_tubes()
 
         self.watch_for_tubes()
 
         self._want_document = True;
 
         self._want_document = True;
Line 380: Line 390:  
     # a stream tube is made available.  
 
     # a stream tube is made available.  
 
     def watch_for_tubes(self):
 
     def watch_for_tubes(self):
        self._update_chat_text('SYSTEM', '_watch_for_tubes()')
   
         tubes_chan = self._shared_activity.telepathy_tubes_chan
 
         tubes_chan = self._shared_activity.telepathy_tubes_chan
   Line 394: Line 403:     
     def _list_tubes_error_cb(self, e):
 
     def _list_tubes_error_cb(self, e):
        self._update_chat_text('System', '_list_tubes_error_cb(): ListTubes() failed: '+str(e))
      
     #### Method _new_tube_cb, which is called once a stream tube is available  
 
     #### Method _new_tube_cb, which is called once a stream tube is available  
Line 400: Line 408:  
     def _new_tube_cb(self, tube_id, initiator, tube_type, service, params,
 
     def _new_tube_cb(self, tube_id, initiator, tube_type, service, params,
 
                     state):
 
                     state):
        self._update_chat_text('SYSTEM', '_new_tube_cb() -- ID:' + str(tube_id) + '; Initiator: ' + str(initiator) + '; tube_type: ' + str(tube_type) + '; Service: ' + str(service))
  −
   
         # If the available tube is the stream tube we set up in sharing activity, then  
 
         # If the available tube is the stream tube we set up in sharing activity, then  
 
         # let's download from it.  
 
         # let's download from it.  
         if service == ANNOTATE_STREAM_SERVICE:
+
         if service == ANNOTATE_STREAM_SERVICE:          
            self._update_chat_text('SYSTEM', 'I could download from that tube')
  −
           
   
             # Add the newly found stream tube to the available tubes we can download from
 
             # Add the newly found stream tube to the available tubes we can download from
 
             self.unused_download_tubes.add(tube_id)
 
             self.unused_download_tubes.add(tube_id)
Line 419: Line 423:  
     # obtained and saved in self.unused_download_tubes.  
 
     # obtained and saved in self.unused_download_tubes.  
 
     def _get_document(self):
 
     def _get_document(self):
        self._update_chat_text('SYSTEM', '_get_document()')
   
         if not self._want_document:
 
         if not self._want_document:
 
             return False
 
             return False
Line 431: Line 434:  
             tube_id = self.unused_download_tubes.pop()
 
             tube_id = self.unused_download_tubes.pop()
 
         except (ValueError, KeyError), e:
 
         except (ValueError, KeyError), e:
            self._update_chat_text('System', 'No tubes to get the document from right now: '+str(e))
   
             return False
 
             return False
   Line 442: Line 444:  
     #### Method _download_result_cb, which is called once downloading is complete.  
 
     #### Method _download_result_cb, which is called once downloading is complete.  
 
     def _download_result_cb(self, getter, tempfile, suggested_name, tube_id):
 
     def _download_result_cb(self, getter, tempfile, suggested_name, tube_id):
        self._update_chat_text('SYSTEM', '_download_result_cb() -- tempfile = ' + tempfile)
   
         del self.unused_download_tubes
 
         del self.unused_download_tubes
  −
        self._update_chat_text('SYSTEM', "Got document %s (%s) from tube %u",
  −
                      tempfile, suggested_name, tube_id)
   
         self.save()
 
         self.save()
   Line 453: Line 451:  
         # FIXME: signal the expected size somehow, so we can draw a progress
 
         # FIXME: signal the expected size somehow, so we can draw a progress
 
         # bar
 
         # bar
         self._update_chat_text("Downloaded " + str(bytes_downloaded) + " bytes from tube " + str(tube_id))
+
         return True;
    
     #### Method _download_error_cb, which is called if there was an error downloading.  
 
     #### Method _download_error_cb, which is called if there was an error downloading.  
Line 466: Line 464:  
         # FIXME: should ideally have the CM listen on a Unix socket
 
         # FIXME: should ideally have the CM listen on a Unix socket
 
         # instead of IPv4 (might be more compatible with Rainbow)
 
         # instead of IPv4 (might be more compatible with Rainbow)
        self._update_chat_text('SYSTEM', '_download_document() -- ' + path)
   
         chan = self._shared_activity.telepathy_tubes_chan
 
         chan = self._shared_activity.telepathy_tubes_chan
 
         iface = chan[telepathy.CHANNEL_TYPE_TUBES]
 
         iface = chan[telepathy.CHANNEL_TYPE_TUBES]
Line 479: Line 476:  
         assert isinstance(addr[0], str)
 
         assert isinstance(addr[0], str)
 
         assert isinstance(addr[1], (int, long))
 
         assert isinstance(addr[1], (int, long))
         assert addr[1] > 0 and addr[1] < 65536
+
         assert 0 < addr[1] < 65536
 
         port = int(addr[1])
 
         port = int(addr[1])
   Line 487: Line 484:  
         getter.connect("progress", self._download_progress_cb, tube_id)
 
         getter.connect("progress", self._download_progress_cb, tube_id)
 
         getter.connect("error", self._download_error_cb, tube_id)
 
         getter.connect("error", self._download_error_cb, tube_id)
        self._update_chat_text('System', "Starting download to "+str(path))
   
         getter.start(path)
 
         getter.start(path)
 
         return False
 
         return False
Line 499: Line 495:     
=== Where do I get more information regarding sugar activity sharing and the technologies that support it? ===
 
=== Where do I get more information regarding sugar activity sharing and the technologies that support it? ===
* A [[Shared_Sugar_Activities | brief tutorial]] on activity sharing for the OLPC laptop.
+
* A [[Development Team/Almanac/Shared_Sugar_Activities | brief tutorial]] on activity sharing for the OLPC laptop.
 +
 
 +
=== I can't get tubes to work.  Are there unresolved issues? ===
 +
 
 +
==== Which threading patterns are most appropriate for use on the sugar platform? ====
 +
 
 +
<p>
 +
There are issues regarding the best way to create activities that support media sharing. In particular, the structure of DBus tubes makes it easy to customize the communication process between activity instances running on multiple XOs. However, stream tubes seem to be tied closely to a client server architecture - the servers and handlers provided in sugar.network package are some form of client/server arrangement.
 +
</p>
 +
 
 +
<p>
 +
Setting up more advanced stream tubes functionality that would allow sharing of non-text data (eg. binary files, images, etc.) in a continuous manner in the way dbus tubes enable text communication is complicated.  To allow activities to communicate constantly over a stream tube, one needs to set up both a client and server side on each activity and coordinate communication between them. Furthermore, most activities would require threading as well, which means resolving best practices for threading. Ultimately, it seems that the existing servers/handlers to support stream tubes may not be adequate to support easy and relatively painless sharing of data between activities on a continuous basis. The code that is on the Almanac right now guides a user through the basic process of setting up a stream tube and allowing communication one time between the server and client. This is useful for sharing/joining activities that require sending binary files (which is why Record and Read use this). However, it does not extend easily to peer to peer communication.
 +
</p>
 +
 
 +
<p>
 +
One solution to sending non-text data between activities is to just use the DBus tube and take advantage of its flexibility. It's not clear how well these tubes will support binary data, however and whether they work well with larger media files. It would be helpful to get insight from sugar developers regarding how such communication should work and what facilities sugar needs to add to support this (perhaps more functionality for stream tubes in sugar.network). Given that peer to peer networking through mesh is probably one of the standout features of XO laptops, I think having better functionality (and better documentation) for developers to build rich communicative applications is a high priority.
 +
</p>

Navigation menu