Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/tutorius
diff options
context:
space:
mode:
authormike <michael.jmontcalm@gmail.com>2009-11-08 03:26:16 (GMT)
committer mike <michael.jmontcalm@gmail.com>2009-11-08 03:26:16 (GMT)
commit80ebf5d2fc91e0e9359becdd0b344332063951ab (patch)
tree1ebbe610ea58d9d88cf74624a418d7e5f8815abe /tutorius
parent5491c551a2f88dbda852bc0e9d0c5406019e2be8 (diff)
parentb3039144e050555ad93c1ab18ae228b5b1970fb5 (diff)
Merge branch 'engine_tutorial_ADT_migration' of ../mainline
Diffstat (limited to 'tutorius')
-rw-r--r--tutorius/TProbe.py140
-rw-r--r--tutorius/service.py63
2 files changed, 167 insertions, 36 deletions
diff --git a/tutorius/TProbe.py b/tutorius/TProbe.py
index f55547c..08c9651 100644
--- a/tutorius/TProbe.py
+++ b/tutorius/TProbe.py
@@ -38,45 +38,65 @@ class TProbe(dbus.service.Object):
a DBUS Interface.
"""
- def __init__(self, activity_name, activity):
+ def __init__(self, activity, service_proxy=None):
"""
Create and register a TProbe for an activity.
- @param activity_name unique activity_id
@param activity activity reference, must be a gtk container
+ @param service_proxy
"""
- LOGGER.debug("TProbe :: Creating TProbe for %s (%d)", activity_name, os.getpid())
- LOGGER.debug("TProbe :: Current gobject context: %s", str(gobject.main_context_default()))
- LOGGER.debug("TProbe :: Current gobject depth: %s", str(gobject.main_depth()))
# Moving the ObjectStore assignment here, in the meantime
# the reference to the activity shouldn't be share as a
# global variable but passed by the Probe to the objects
# that requires it
self._activity = activity
+
+ if service_proxy == None:
+ from .service import ServiceProxy
+
+ self._service_proxy = service_proxy or ServiceProxy()
ObjectStore().activity = activity
- self._activity_name = activity_name
+ self._activity_name = activity.get_bundle_id()
+ self._unique_id = activity.get_id()
+
+ LOGGER.debug("TProbe :: Creating TProbe for %s (%d)", self._activity_name, os.getpid())
+ LOGGER.debug("TProbe :: Current gobject context: %s", str(gobject.main_context_default()))
+ LOGGER.debug("TProbe :: Current gobject depth: %s", str(gobject.main_depth()))
self._session_bus = dbus.SessionBus()
# Giving a new name because _name is already used by dbus
- self._name2 = dbus.service.BusName(activity_name, self._session_bus)
- dbus.service.Object.__init__(self, self._session_bus, "/tutorius/Probe")
+ self._name2 = dbus.service.BusName(self._activity_name, self._session_bus)
+ dbus.service.Object.__init__(self, self._session_bus, "/tutorius/Probe/"+str(self._unique_id))
# Add the dictionary we will use to store which actions and events
# are known
self._installedActions = {}
self._subscribedEvents = {}
+ LOGGER.debug("TProbe :: registering '%s' with unique_id '%s'", self._activity_name, activity.get_id())
+ self._service_proxy.register_probe(self._activity_name, self._unique_id)
+
+
+
def start(self):
"""
Optional method to call if the probe is not inserted into an
existing activity. Starts a gobject mainloop
"""
mainloop = gobject.MainLoop()
- print "Starting Probe for " + self._activity_name
mainloop.run()
+ def stop(self):
+ """
+ Clean up the probe when finished. Should be called just
+ before a process ends
+ """
+ from .service import ServiceProxy
+ LOGGER.debug("TProbe :: unregistering '%s' with unique_id '%s'", self._activity_name, self._unique_id)
+ ServiceProxy().unregister_probe(self._unique_id)
+
@dbus.service.method("org.tutorius.ProbeInterface",
in_signature='s', out_signature='')
def registered(self, service):
@@ -234,16 +254,17 @@ class ProbeProxy:
It provides an object interface to the TProbe, which requires pickled
strings, across a DBus communication.
"""
- def __init__(self, activityName):
+ def __init__(self, activityName, unique_id):
"""
Constructor
- @param activityName unique activity id. Must be a valid dbus bus name.
+ @param activityName generic activity name. Must be a valid dbus bus name.
+ @param unique_id unique id specific to an instance of an activity
"""
LOGGER.debug("ProbeProxy :: Creating ProbeProxy for %s (%d)", activityName, os.getpid())
LOGGER.debug("ProbeProxy :: Current gobject context: %s", str(gobject.main_context_default()))
LOGGER.debug("ProbeProxy :: Current gobject depth: %s", str(gobject.main_depth()))
bus = dbus.SessionBus()
- self._object = bus.get_object(activityName, "/tutorius/Probe")
+ self._object = bus.get_object(activityName, "/tutorius/Probe/"+str(unique_id))
self._probe = dbus.Interface(self._object, "org.tutorius.ProbeInterface")
self._actions = {}
@@ -397,7 +418,7 @@ class ProbeProxy:
return_cb=save_args(self.__clear_event, address),
block=block)
else:
- LOGGER.debug("ProbeProxy :: unsubsribe address %s failed : not registered", address)
+ LOGGER.debug("ProbeProxy :: unsubscribe address %s failed : not registered", address)
def detach(self, block=False):
"""
@@ -418,16 +439,22 @@ class ProbeManager(object):
For now, it only handles one at a time, though.
Actually it doesn't do much at all. But it keeps your encapsulation happy
"""
+ _LOGGER = logging.getLogger("sugar.tutorius.ProbeManager")
+
def __init__(self, proxy_class=ProbeProxy):
"""Constructor
@param proxy_class Class to use for creating Proxies to activities.
The class should support the same interface as ProbeProxy. Exists
to make this class unit-testable by replacing the Proxy with a mock
"""
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
self._ProxyClass = proxy_class
self._probes = {}
self._current_activity = None
+ ProbeManager._LOGGER.debug("__init__()")
+
def setCurrentActivity(self, activity_id):
if not activity_id in self._probes:
raise RuntimeError("Activity not attached")
@@ -437,23 +464,6 @@ class ProbeManager(object):
return self._current_activity
currentActivity = property(fget=getCurrentActivity, fset=setCurrentActivity)
- def attach(self, activity_id):
- if activity_id in self._probes:
- raise RuntimeWarning("Activity already attached")
-
- self._probes[activity_id] = self._ProxyClass(activity_id)
- #TODO what do we do with this? Raise something?
- if self._probes[activity_id].isAlive():
- print "Alive!"
- else:
- print "FAil!"
-
- def detach(self, activity_id):
- if activity_id in self._probes:
- probe = self._probes.pop(activity_id)
- probe.detach()
- if self._current_activity == activity_id:
- self._current_activity = None
def install(self, action, block=False):
"""
@@ -463,7 +473,7 @@ class ProbeManager(object):
@return None
"""
if self.currentActivity:
- return self._probes[self.currentActivity].install(action, block)
+ return self._first_proxy(self.currentActivity).install(action, block)
else:
raise RuntimeWarning("No activity attached")
@@ -476,7 +486,7 @@ class ProbeManager(object):
@return None
"""
if self.currentActivity:
- return self._probes[self.currentActivity].update(action, newaction, block)
+ return self._first_proxy(self.currentActivity).update(action, newaction, block)
else:
raise RuntimeWarning("No activity attached")
@@ -487,7 +497,7 @@ class ProbeManager(object):
@param block Force a synchroneous dbus call if True
"""
if self.currentActivity:
- return self._probes[self.currentActivity].uninstall(action, block)
+ return self._first_proxy(self.currentActivity).uninstall(action, block)
else:
raise RuntimeWarning("No activity attached")
@@ -499,7 +509,7 @@ class ProbeManager(object):
@return address identifier used for unsubscribing
"""
if self.currentActivity:
- return self._probes[self.currentActivity].subscribe(event, callback)
+ return self._first_proxy(self.currentActivity).subscribe(event, callback)
else:
raise RuntimeWarning("No activity attached")
@@ -510,7 +520,67 @@ class ProbeManager(object):
@return None
"""
if self.currentActivity:
- return self._probes[self.currentActivity].unsubscribe(address)
+ return self._first_proxy(self.currentActivity).unsubscribe(address)
else:
raise RuntimeWarning("No activity attached")
+ def register_probe(self, process_name, unique_id):
+ """ Adds a probe to the known probes, to be used by a tutorial.
+
+ A generic name for a process (like an Activity) is passed
+ so that the execution of a tutorial will use that generic
+ name. However, a unique id is also passed to differentiate
+ between many instances of the same process.
+
+ @param process_name The generic name of a process
+ @param unique_id The unique identification associated to this
+ process
+ """
+ ProbeManager._LOGGER.debug("register_probe(%s,%s)", process_name, unique_id)
+ if process_name not in self._probes:
+ self._probes[process_name] = [(unique_id,self._ProxyClass(process_name, unique_id))]
+ else:
+ self._probes[process_name].append((unique_id,self._ProxyClass(process_name, unique_id)))
+
+
+ def unregister_probe(self, unique_id):
+ """ Remove a probe from the known probes.
+
+ @param unique_id The unique identification associated to this
+ process
+ """
+ ProbeManager._LOGGER.debug("unregister_probe(%s)", unique_id)
+ for process_name, proxies in self._probes.items():
+ for id, proxy in proxies:
+ if unique_id == id:
+ proxy.detach()
+ proxies.remove((id,proxy))
+ if len(proxies) == 0:
+ self._probes.pop(process_name)
+
+ def get_registered_probes_list(self, process_name=None):
+ if process_name == None:
+ probe_list = []
+ for probes in self._probes.itervalues():
+ probe_list.extend(probes)
+ return probe_list
+ else:
+ if process_name in self._probes:
+ return self._probes[process_name]
+ else:
+ return []
+
+
+
+ def _first_proxy(self, process_name):
+ """
+ Returns the oldest probe connected under the process_name
+ @param process_name The generic process name under which the probe
+ is connected
+ """
+ if process_name in self._probes:
+ return self._probes[process_name][0][1]
+ else:
+ raise RuntimeWarning("No activity attached under '%s'", process_name)
+
+
diff --git a/tutorius/service.py b/tutorius/service.py
index eb246a1..8694cb5 100644
--- a/tutorius/service.py
+++ b/tutorius/service.py
@@ -2,6 +2,9 @@ import dbus
from .engine import Engine
from .dbustools import remote_call
+from .TProbe import ProbeManager
+import logging
+LOGGER = logging.getLogger("sugar.tutorius.service")
_DBUS_SERVICE = "org.tutorius.Service"
_DBUS_PATH = "/org/tutorius/Service"
@@ -19,11 +22,13 @@ class Service(dbus.service.Object):
self._engine = None
+ self._probeMgr = ProbeManager()
+
def start(self):
""" Start the service itself
"""
# For the moment there is nothing to do
- pass
+ LOGGER.debug("Service.start()")
@dbus.service.method(_DBUS_SERVICE_IFACE,
@@ -50,6 +55,35 @@ class Service(dbus.service.Object):
"""
self._engine.pause()
+ @dbus.service.method(_DBUS_SERVICE_IFACE,
+ in_signature="ss", out_signature="")
+ def register_probe(self, process_name, unique_id):
+ """ Adds a probe to the known probes, to be used by a tutorial.
+
+ A generic name for a process (like an Activity) is passed
+ so that the execution of a tutorial will use that generic
+ name. However, a unique id is also passed to differentiate
+ between many instances of the same process.
+
+ @param process_name The generic name of a process
+ @param unique_id The unique identification associated to this
+ process
+ """
+ LOGGER.debug("Service.register_probe(%s,%s)", process_name, unique_id)
+ self._probeMgr.register_probe(process_name, unique_id)
+
+ @dbus.service.method(_DBUS_SERVICE_IFACE,
+ in_signature="s", out_signature="")
+ def unregister_probe(self, unique_id):
+ """ Remove a probe from the known probes.
+
+ @param process_name The generic name of a process
+ @param unique_id The unique identification associated to this
+ process
+ """
+ LOGGER.debug("Service.unregister_probe(%s)", unique_id)
+ self._probeMgr.unregister_probe(unique_id)
+
class ServiceProxy:
""" Proxy to connect to the Service object, abstracting the DBus interface"""
@@ -74,6 +108,33 @@ class ServiceProxy:
"""
remote_call(self._service.pause, (), block=False)
+ def register_probe(self, process_name, unique_id):
+ """ Adds a probe to the known probes, to be used by a tutorial.
+
+ A generic name for a process (like an Activity) is passed
+ so that the execution of a tutorial will use that generic
+ name. However, a unique id is also passed to differentiate
+ between many instances of the same process.
+
+ @param process_name The generic name of a process
+ @param unique_id The unique identification associated to this
+ process
+ """
+ remote_call(self._service.register_probe, (process_name,unique_id), block=False)
+
+ def unregister_probe(self, unique_id):
+ """ Remove a probe from the known probes.
+
+ @param process_name The generic name of a process
+ @param unique_id The unique identification associated to this
+ process
+ """
+ # We make it synchronous because otherwise on closing,
+ # activities kill the dbus session bus too fast for the
+ # asynchronous call to be completed
+ self._service.unregister_probe(unique_id)
+
+
if __name__ == "__main__":
import dbus.mainloop.glib
import gobject