changeset 1622:5b24d6bf5d15

core, bridge: actionsGet: - added a new mechanism to keep actions until they are answered (or timeout-ed) - keep_id must be explicitly used on actionNew - actionsGet is used to retrive these actions - the mechanism is used in deferXMLUI
author Goffi <goffi@goffi.org>
date Tue, 17 Nov 2015 21:28:58 +0100
parents a17a91531fbe
children ec48b35309dc
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 src/tools/xml_tools.py
diffstat 6 files changed, 63 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/frontends/src/bridge/DBus.py	Tue Nov 17 20:18:51 2015 +0100
+++ b/frontends/src/bridge/DBus.py	Tue Nov 17 21:28:58 2015 +0100
@@ -123,6 +123,20 @@
 
             return getPluginMethod
 
+    def actionsGet(self, profile_key="@DEFAULT@", 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.actionsGet(profile_key, **kwargs)
+
     def addContact(self, entity_jid, profile_key="@DEFAULT@", callback=None, errback=None):
         if callback is None:
             error_handler = None
--- a/src/bridge/DBus.py	Tue Nov 17 20:18:51 2015 +0100
+++ b/src/bridge/DBus.py	Tue Nov 17 21:28:58 2015 +0100
@@ -213,6 +213,12 @@
     ### methods ###
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
+                         in_signature='s', out_signature='a(a{ss}si)',
+                         async_callbacks=None)
+    def actionsGet(self, profile_key="@DEFAULT@"):
+        return self._callback("actionsGet", unicode(profile_key))
+
+    @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ss', out_signature='',
                          async_callbacks=None)
     def addContact(self, entity_jid, profile_key="@DEFAULT@"):
--- a/src/bridge/bridge_constructor/bridge_template.ini	Tue Nov 17 20:18:51 2015 +0100
+++ b/src/bridge/bridge_constructor/bridge_template.ini	Tue Nov 17 21:28:58 2015 +0100
@@ -632,6 +632,16 @@
 doc_return=dict where key can be:
     - xmlui: a XMLUI need to be displayed
 
+[actionsGet]
+type=method
+category=core
+sig_in=s
+sig_out=a(a{ss}si)
+param_0_default="@DEFAULT@"
+doc=Get all not yet answered actions
+doc_param_0=%(doc_profile_key)s
+doc_return=list of data as for [actionNew] (without the profile)
+
 [confirmationAnswer]
 deprecated=
 type=method
--- a/src/core/sat_main.py	Tue Nov 17 20:18:51 2015 +0100
+++ b/src/core/sat_main.py	Tue Nov 17 21:28:58 2015 +0100
@@ -102,6 +102,7 @@
         self.bridge.register("delContact", self._delContact)
         self.bridge.register("isConnected", self.isConnected)
         self.bridge.register("launchAction", self.launchCallback)
+        self.bridge.register("actionsGet", self.actionsGet)
         self.bridge.register("confirmationAnswer", self.confirmationAnswer)
         self.bridge.register("progressGet", self._progressGet)
         self.bridge.register("progressGetAll", self._progressGetAll)
@@ -785,16 +786,36 @@
             del client._waiting_conf[conf_id]
             cb(conf_id, accepted, data, profile)
 
-    def actionNew(self, action_data, security_limit=C.NO_SECURITY_LIMIT, profile=C.PROF_KEY_NONE):
-        """Shortcut to bridge.actionNew which generate and id
+    def _killAction(self, keep_id, client):
+        log.debug(u"Killing action {} for timeout".format(keep_id))
+        client.actions[keep_id]
+
+    def actionNew(self, action_data, security_limit=C.NO_SECURITY_LIMIT, keep_id=None, profile=C.PROF_KEY_NONE):
+        """Shortcut to bridge.actionNew which generate and id and keep for retrieval
 
         @param action_data(dict): action data (see bridge documentation)
         @param security_limit: %(doc_security_limit)s
+        @param keep_id(None, unicode): if not None, used to keep action for differed retrieval
+            must be set to the callback_id
+            action will be deleted after 30 min.
         @param profile: %(doc_profile)s
         """
         id_ = unicode(uuid.uuid4())
+        if keep_id is not None:
+            client = self.getClient(profile)
+            action_timer = reactor.callLater(60*30, self._killAction)
+            client.actions[keep_id] = (action_data, id_, security_limit, action_timer)
+
         self.bridge.actionNew(action_data, id_, security_limit, profile)
 
+    def actionsGet(self, profile):
+        """Return current non answered actions
+
+        @param profile: %(doc_profile)s
+        """
+        client = self.getClient(profile)
+        return [action_tuple[:-1] for action_tuple in client.actions.itervalues()]
+
     def registerProgressCb(self, progress_id, callback, profile):
         """Register a callback called when progress is requested for id"""
         client = self.getClient(profile)
@@ -904,9 +925,13 @@
                 - C.BOOL_TRUE
                 - C.BOOL_FALSE
         """
-        profile = self.memory.getProfileName(profile_key)
-        if not profile:
-            raise exceptions.ProfileUnknownError(_('trying to launch action with a non-existant profile'))
+        client = self.getClient(profile_key)
+        try:
+            action_tuple = client.actions[callback_id]
+        except KeyError:
+            pass
+        else:
+            action_tuple[-1].cancel() # the last item is the action timer
 
         try:
             callback, args, kwargs = self._cb_map[callback_id]
@@ -918,7 +943,7 @@
                 raise exceptions.DataError("Required data for this callback is missing")
             args,kwargs=list(args)[:],kwargs.copy() # we don't want to modify the original (kw)args
             args.insert(0, data)
-            kwargs["profile"] = profile
+            kwargs["profile"] = client.profile
             del kwargs["with_data"]
 
         if kwargs.pop('one_shot', False):
--- a/src/core/xmpp.py	Tue Nov 17 20:18:51 2015 +0100
+++ b/src/core/xmpp.py	Tue Nov 17 21:28:58 2015 +0100
@@ -45,6 +45,7 @@
         self.conn_deferred = defer.Deferred()
         self._waiting_conf = {}  # callback called when a confirmation is received
         self._progress_cb = {}  # callback called when a progress is requested (key = progress id)
+        self.actions = {} # used to keep track of actions for retrieval (key = action_id)
 
     def getConnectionDeferred(self):
         """Return a deferred which fire when the client is connected"""
--- a/src/tools/xml_tools.py	Tue Nov 17 20:18:51 2015 +0100
+++ b/src/tools/xml_tools.py	Tue Nov 17 21:28:58 2015 +0100
@@ -1271,7 +1271,7 @@
     action_data = {'xmlui': xmlui.toXml()}
     if action_extra is not None:
         action_data.update(action_extra)
-    host.actionNew(action_data, profile=profile)
+    host.actionNew(action_data, keep_id=xmlui.submit_id, profile=profile)
     return xmlui_d
 
 def deferDialog(host, message, title=u'Please confirm', type_=C.XMLUI_DIALOG_CONFIRM, options=None,