changeset 1522:7d7e57a84792

core: progression handling improvments: - getProgress has been renamed to progressGet to follown new naming convention - new signals: progressStarted, progressFinished and progressError to indicate state of progressing events - new method progressGetAll to get all progressing events of all profile (or only one profile)
author Goffi <goffi@goffi.org>
date Fri, 25 Sep 2015 19:19:12 +0200
parents d2ab9c62ac3a
children 0209f8d35873
files frontends/src/bridge/DBus.py src/bridge/DBus.py src/bridge/bridge_constructor/bridge_template.ini src/core/sat_main.py src/core/xmpp.py
diffstat 5 files changed, 166 insertions(+), 42 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/bridge/DBus.py	Fri Sep 25 19:19:12 2015 +0200
+++ b/frontends/src/bridge/DBus.py	Fri Sep 25 19:19:12 2015 +0200
@@ -450,20 +450,6 @@
             kwargs['error_handler'] = error_handler
         return self.db_core_iface.getProfilesList(**kwargs)
 
-    def getProgress(self, id, profile, callback=None, errback=None):
-        if callback is None:
-            error_handler = None
-        else:
-            if errback is None:
-                errback = log.error
-            error_handler = lambda err:errback(dbus_to_bridge_exception(err))
-        kwargs={}
-        if callback is not None:
-            kwargs['timeout'] = const_TIMEOUT
-            kwargs['reply_handler'] = callback
-            kwargs['error_handler'] = error_handler
-        return self.db_core_iface.getProgress(id, profile, **kwargs)
-
     def getReady(self, callback=None, errback=None):
         if callback is None:
             error_handler = None
@@ -566,6 +552,34 @@
             kwargs['error_handler'] = error_handler
         return self.db_core_iface.paramsRegisterApp(xml, security_limit, app, **kwargs)
 
+    def progressGet(self, id, profile, callback=None, errback=None):
+        if callback is None:
+            error_handler = None
+        else:
+            if errback is None:
+                errback = log.error
+            error_handler = lambda err:errback(dbus_to_bridge_exception(err))
+        kwargs={}
+        if callback is not None:
+            kwargs['timeout'] = const_TIMEOUT
+            kwargs['reply_handler'] = callback
+            kwargs['error_handler'] = error_handler
+        return self.db_core_iface.progressGet(id, profile, **kwargs)
+
+    def progressGetAll(self, profile, callback=None, errback=None):
+        if callback is None:
+            error_handler = None
+        else:
+            if errback is None:
+                errback = log.error
+            error_handler = lambda err:errback(dbus_to_bridge_exception(err))
+        kwargs={}
+        if callback is not None:
+            kwargs['timeout'] = const_TIMEOUT
+            kwargs['reply_handler'] = callback
+            kwargs['error_handler'] = error_handler
+        return self.db_core_iface.progressGetAll(profile, **kwargs)
+
     def saveParamsTemplate(self, filename, callback=None, errback=None):
         if callback is None:
             error_handler = None
--- a/src/bridge/DBus.py	Fri Sep 25 19:19:12 2015 +0200
+++ b/src/bridge/DBus.py	Fri Sep 25 19:19:12 2015 +0200
@@ -192,6 +192,21 @@
 
     @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX,
                          signature='sss')
+    def progressError(self, error, profile, arg_2):
+        pass
+
+    @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX,
+                         signature='ss')
+    def progressFinished(self, id, profile):
+        pass
+
+    @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX,
+                         signature='ss')
+    def progressStarted(self, id, profile):
+        pass
+
+    @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX,
+                         signature='sss')
     def subscribe(self, sub_type, entity_jid, profile):
         pass
 
@@ -366,12 +381,6 @@
         return self._callback("getProfilesList", )
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
-                         in_signature='ss', out_signature='a{ss}',
-                         async_callbacks=None)
-    def getProgress(self, id, profile):
-        return self._callback("getProgress", unicode(id), unicode(profile))
-
-    @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='', out_signature='',
                          async_callbacks=('callback', 'errback'))
     def getReady(self, callback=None, errback=None):
@@ -420,6 +429,18 @@
         return self._callback("paramsRegisterApp", unicode(xml), security_limit, unicode(app))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
+                         in_signature='ss', out_signature='a{ss}',
+                         async_callbacks=None)
+    def progressGet(self, id, profile):
+        return self._callback("progressGet", unicode(id), unicode(profile))
+
+    @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
+                         in_signature='s', out_signature='a{sa{sa{ss}}}',
+                         async_callbacks=None)
+    def progressGetAll(self, profile):
+        return self._callback("progressGetAll", unicode(profile))
+
+    @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='b',
                          async_callbacks=None)
     def saveParamsTemplate(self, filename):
@@ -596,6 +617,15 @@
     def presenceUpdate(self, entity_jid, show, priority, statuses, profile):
         self.dbus_bridge.presenceUpdate(entity_jid, show, priority, statuses, profile)
 
+    def progressError(self, error, profile, arg_2):
+        self.dbus_bridge.progressError(error, profile, arg_2)
+
+    def progressFinished(self, id, profile):
+        self.dbus_bridge.progressFinished(id, profile)
+
+    def progressStarted(self, id, profile):
+        self.dbus_bridge.progressStarted(id, profile)
+
     def subscribe(self, sub_type, entity_jid, profile):
         self.dbus_bridge.subscribe(sub_type, entity_jid, profile)
 
--- a/src/bridge/bridge_constructor/bridge_template.ini	Fri Sep 25 19:19:12 2015 +0200
+++ b/src/bridge/bridge_constructor/bridge_template.ini	Fri Sep 25 19:19:12 2015 +0200
@@ -158,6 +158,31 @@
 doc_param_2=value: New value
 doc_param_3=%(doc_profile)s
 
+[progressStarted]
+type=signal
+category=core
+sig_in=ss
+doc=A progressing operation has just started
+doc_param_0=id: id of the progression operation
+doc_param_1=%(doc_profile)s
+
+[progressFinished]
+type=signal
+category=core
+sig_in=ss
+doc=A progressing operation is finished
+doc_param_0=id: id of the progression operation
+doc_param_1=%(doc_profile)s
+
+[progressError]
+type=signal
+category=core
+sig_in=sss
+doc=There was an error during progressing operation
+doc_param_0=id: id of the progression operation
+doc_param_0=error: error message
+doc_param_1=%(doc_profile)s
+
 ;methods
 
 [getReady]
@@ -595,7 +620,7 @@
 doc_param_2=data: action specific data
 doc_param_3=%(doc_profile)s
 
-[getProgress]
+[progressGet]
 type=method
 category=core
 sig_in=ss
@@ -603,10 +628,21 @@
 doc=Get progress information for an action
 doc_param_0=id: id of the progression status
 doc_param_1=%(doc_profile)s
-doc_return=dict with progress information:
+doc_return=dict with progress informations:
  - position: current position
  - size: end position
 
+[progressGetAll]
+type=method
+category=core
+sig_in=s
+sig_out=a{sa{sa{ss}}}
+doc=Get all active progress informations
+doc_param_0=%(doc_profile)s or C.PROF_KEY_ALL for all profiles
+doc_return= a dict which map profile to progress_dict
+    progress_dict map progress_id to progress_data
+    progress_data is the same dict as returned by [progressGet]
+
 [getMenus]
 type=method
 category=core
--- a/src/core/sat_main.py	Fri Sep 25 19:19:12 2015 +0200
+++ b/src/core/sat_main.py	Fri Sep 25 19:19:12 2015 +0200
@@ -121,7 +121,8 @@
         self.bridge.register("isConnected", self.isConnected)
         self.bridge.register("launchAction", self.launchCallback)
         self.bridge.register("confirmationAnswer", self.confirmationAnswer)
-        self.bridge.register("getProgress", self.getProgress)
+        self.bridge.register("progressGet", self._progressGet)
+        self.bridge.register("progressGetAll", self._progressGetAll)
         self.bridge.register("getMenus", self.getMenus)
         self.bridge.register("getMenuHelp", self.getMenuHelp)
         self.bridge.register("discoInfos", self.memory.disco._discoInfos)
@@ -449,15 +450,18 @@
         return self.profiles[profile]
 
     def getClients(self, profile_key):
-        """Convenient method to get list of clients from profile key (manage list through profile_key like @ALL@)
+        """Convenient method to get list of clients from profile key (manage list through profile_key like C.PROF_KEY_ALL)
+
         @param profile_key: %(doc_profile_key)s
-        @return: list of clients"""
-        profile = self.memory.getProfileName(profile_key, True)
-        if not profile:
+        @return: list of clients
+        """
+        try:
+            profile = self.memory.getProfileName(profile_key, True)
+        except exceptions.ProfileUnknownError:
             return []
-        if profile == "@ALL@":
+        if profile == C.PROF_KEY_ALL:
             return self.profiles.values()
-        if profile.count('@') > 1:
+        elif profile.count('@') > 1:
             raise exceptions.ProfileKeyUnknownError
         return [self.profiles[profile]]
 
@@ -779,33 +783,73 @@
         id_ = unicode(uuid.uuid4())
         self.bridge.actionNew(action_data, id_, profile)
 
-    def registerProgressCB(self, progress_id, CB, profile):
+    def registerProgressCb(self, progress_id, callback, profile):
         """Register a callback called when progress is requested for id"""
         client = self.getClient(profile)
-        client._progress_cb_map[progress_id] = CB
+        if progress_id in client._progress_cb:
+            raise exceptions.ConflictError(u"Progress ID is not unique !")
+        client._progress_cb[progress_id] = callback
 
-    def removeProgressCB(self, progress_id, profile):
+    def removeProgressCb(self, progress_id, profile):
         """Remove a progress callback"""
         client = self.getClient(profile)
-        if progress_id not in client._progress_cb_map:
+        try:
+            del client._progress_cb[progress_id]
+        except KeyError:
             log.error(_("Trying to remove an unknow progress callback"))
-        else:
-            del client._progress_cb_map[progress_id]
+            import ipdb; ipdb.set_trace()
+
+    def _progressGet(self, progress_id, profile):
+        data = self.progressGet(progress_id, profile)
+        return {k: unicode(v) for k,v in data}
 
-    def getProgress(self, progress_id, profile):
+    def progressGet(self, progress_id, profile):
         """Return a dict with progress information
-        data['position'] : current possition
-        data['size'] : end_position
+
+        @param progress_id(unicode): unique id of the progressing element
+        @param profile: %(doc_profile)s
+        @return (dict): data with the following keys:
+            'position' (int): current possition
+            'size' (int): end_position
+            if id doesn't exists (may be a finished progression), and empty dict is returned
         """
         client = self.getClient(profile)
         data = {}
         try:
-            client._progress_cb_map[progress_id](progress_id, data, profile)
+            client._progress_cb[progress_id](progress_id, data, profile)
         except KeyError:
-            pass
-            #log.debug("Requested progress for unknown progress_id")
+            log.debug("Requested progress for unknown progress_id")
         return data
 
+    def _progressGetAll(self, profile_key):
+        progress_all = self.progressGetAll(profile_key)
+        for profile, progress_dict in progress_all.iteritems():
+            for progress_id, data in progress_dict.iteritems():
+                for key, value in data.iteritems():
+                    data[key] = unicode(value)
+        return progress_all
+
+    def progressGetAll(self, profile_key):
+        """Return all progress informations
+
+        @param profile_key: %(doc_profile)s get all progress from this profile
+            if C.PROF_KEY_ALL is used, all progress from all profiles are returned
+        @return (dict[dict]): key=progress id, value=dict of data with the following keys:
+            'position' (int): current possition
+            'size' (int): end_position
+        """
+        clients = self.getClients(profile_key)
+        progress_all = {}
+        for client in clients:
+            profile = client.profile
+            progress_dict = {}
+            progress_all[profile] = progress_dict
+            for progress_id, progress_cb in client._progress_cb.iteritems():
+                data = {}
+                progress_dict[progress_id] = data
+                progress_dict[progress_id] = progress_cb(progress_id, data, profile)
+        return progress_all
+
     def registerCallback(self, callback, *args, **kwargs):
         """ Register a callback.
         Use with_data=True in kwargs if the callback use the optional data dict
--- a/src/core/xmpp.py	Fri Sep 25 19:19:12 2015 +0200
+++ b/src/core/xmpp.py	Fri Sep 25 19:19:12 2015 +0200
@@ -46,7 +46,7 @@
         self.host_app = host_app
         self.conn_deferred = defer.Deferred()
         self._waiting_conf = {}  # callback called when a confirmation is received
-        self._progress_cb_map = {}  # callback called when a progress is requested (key = progress id)
+        self._progress_cb = {}  # callback called when a progress is requested (key = progress id)
 
     def getConnectionDeferred(self):
         """Return a deferred which fire when the client is connected"""