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
This commit is contained in:
Goffi 2015-11-17 21:28:58 +01:00
commit a42452ff57
6 changed files with 63 additions and 7 deletions

View file

@ -123,6 +123,20 @@ class DBusBridgeFrontend(BridgeFrontend):
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

View file

@ -212,6 +212,12 @@ class DbusObject(dbus.service.Object):
### 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)

View file

@ -632,6 +632,16 @@ doc_param_2=%(doc_profile_key)s
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

View file

@ -102,6 +102,7 @@ class SAT(service.Service):
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 @@ class SAT(service.Service):
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 @@ class SAT(service.Service):
- 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 @@ class SAT(service.Service):
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):

View file

@ -45,6 +45,7 @@ class SatXMPPClient(client.XMPPClient):
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"""

View file

@ -1271,7 +1271,7 @@ def deferXMLUI(host, xmlui, action_extra=None, security_limit=C.NO_SECURITY_LIMI
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,