diff src/bridge/DBus.py @ 423:6c20c76abdcc

backend: - bridge async D-Bus method now automatically manage callback and errback, we just have to return a deferred - getParams, getParamsForCategory and getParamsUI are now asynchronous primitivus: management of asynchronous getParamsUI
author Goffi <goffi@goffi.org>
date Mon, 07 Nov 2011 00:09:22 +0100
parents 6c167a2e04b8
children 72c13313b6d6
line wrap: on
line diff
--- a/src/bridge/DBus.py	Sun Nov 06 15:19:51 2011 +0100
+++ b/src/bridge/DBus.py	Mon Nov 07 00:09:22 2011 +0100
@@ -24,7 +24,8 @@
 import dbus
 import dbus.service
 import dbus.mainloop.glib
-from logging import debug, info
+from logging import debug, info, error
+from twisted.internet.defer import Deferred
 
 const_INT_PREFIX = "org.goffi.SAT"  #Interface prefix
 const_ERROR_PREFIX = const_INT_PREFIX+".error"
@@ -32,10 +33,20 @@
 const_CORE_SUFFIX = ".core"
 const_PLUGIN_SUFFIX = ".plugin"
 
+class MethodNotRegistered(dbus.DBusException):
+    _dbus_error_name = const_ERROR_PREFIX + ".MethodNotRegistered"
+
+class InternalError(dbus.DBusException):
+    _dbus_error_name = const_ERROR_PREFIX + ".InternalError"
+
+class AsyncNotDeferred(dbus.DBusException):
+    _dbus_error_name = const_ERROR_PREFIX + ".AsyncNotDeferred"
+
 class GenericException(dbus.DBusException):
-    def __init__(self, name):
+    def __init__(self, twisted_error):
         super(GenericException,self).__init__()
-        self._dbus_error_name = const_ERROR_PREFIX+"."+name
+        mess = twisted_error.getErrorMessage()
+        self._dbus_error_name = const_ERROR_PREFIX+"."+ (mess or str(err.__class__))
 
 class DbusObject(dbus.service.Object):
 
@@ -47,6 +58,32 @@
     def register(self, name, cb):
         self.cb[name]=cb
 
+    def _callback(self, name, *args, **kwargs):
+        """call the callback if it exists, raise an exception else
+        if the callback return a deferred, use async methods"""
+        if not name in self.cb:
+            raise MethodNotRegistered
+
+        if "callback" in kwargs:
+            #we must have errback too
+            if not "errback" in kwargs:
+                error("errback is missing in method call [%s]" % name)
+                raise InternalError
+            callback = kwargs.pop("callback")
+            errback = kwargs.pop("errback")
+            async = True
+        else:
+            async = False
+        result = self.cb[name](*args, **kwargs)
+        if async:
+            if not isinstance(result, Deferred):
+                error("Asynchrone method [%s] does not return a Deferred." % name)
+                raise AsyncNotDeferred
+            result.addCallback(callback)
+            result.addErrback(lambda err:errback(GenericException(err)))
+        else:
+            return result
+
     ### signals ###    
 
     @dbus.service.signal(const_INT_PREFIX+const_PLUGIN_SUFFIX,
@@ -134,217 +171,217 @@
                          in_signature='ss', out_signature='',
                          async_callbacks=None)
     def addContact(self, entity_jid, profile_key="@DEFAULT@"):
-        return self.cb["addContact"](unicode(entity_jid), unicode(profile_key))
+        return self._callback("addContact", unicode(entity_jid), unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='',
                          async_callbacks=('callback', 'errback'))
     def asyncConnect(self, profile_key="@DEFAULT@", callback=None, errback=None):
-        return self.cb["asyncConnect"](unicode(profile_key), callback, lambda arg:errback(GenericException(arg)))
+        return self._callback("asyncConnect", unicode(profile_key), callback=callback, errback=errback)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='',
                          async_callbacks=('callback', 'errback'))
     def asyncCreateProfile(self, profile, callback=None, errback=None):
-        return self.cb["asyncCreateProfile"](unicode(profile), callback, lambda arg:errback(GenericException(arg)))
+        return self._callback("asyncCreateProfile", unicode(profile), callback=callback, errback=errback)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssss', out_signature='s',
                          async_callbacks=('callback', 'errback'))
     def asyncGetParamA(self, name, category, attribute="value", profile_key="@DEFAULT@", callback=None, errback=None):
-        return self.cb["asyncGetParamA"](unicode(name), unicode(category), unicode(attribute), unicode(profile_key), callback, lambda arg:errback(GenericException(arg)))
+        return self._callback("asyncGetParamA", unicode(name), unicode(category), unicode(attribute), unicode(profile_key), callback=callback, errback=errback)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssss', out_signature='s',
                          async_callbacks=None)
     def callMenu(self, category, name, menu_type, profile_key):
-        return self.cb["callMenu"](unicode(category), unicode(name), unicode(menu_type), unicode(profile_key))
+        return self._callback("callMenu", unicode(category), unicode(name), unicode(menu_type), unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='sba{ss}', out_signature='',
                          async_callbacks=None)
     def confirmationAnswer(self, id, accepted, data):
-        return self.cb["confirmationAnswer"](unicode(id), accepted, data)
+        return self._callback("confirmationAnswer", unicode(id), accepted, data)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='',
                          async_callbacks=None)
     def connect(self, profile_key="@DEFAULT@"):
-        return self.cb["connect"](unicode(profile_key))
+        return self._callback("connect", unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='i',
                          async_callbacks=None)
     def createProfile(self, profile):
-        return self.cb["createProfile"](unicode(profile))
+        return self._callback("createProfile", unicode(profile))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ss', out_signature='',
                          async_callbacks=None)
     def delContact(self, entity_jid, profile_key="@DEFAULT@"):
-        return self.cb["delContact"](unicode(entity_jid), unicode(profile_key))
+        return self._callback("delContact", unicode(entity_jid), unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='i',
                          async_callbacks=None)
     def deleteProfile(self, profile):
-        return self.cb["deleteProfile"](unicode(profile))
+        return self._callback("deleteProfile", unicode(profile))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='',
                          async_callbacks=None)
     def disconnect(self, profile_key="@DEFAULT@"):
-        return self.cb["disconnect"](unicode(profile_key))
+        return self._callback("disconnect", unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ss', out_signature='s',
                          async_callbacks=None)
     def getConfig(self, section, name):
-        return self.cb["getConfig"](unicode(section), unicode(name))
+        return self._callback("getConfig", unicode(section), unicode(name))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='a(sa{ss}as)',
                          async_callbacks=None)
     def getContacts(self, profile_key="@DEFAULT@"):
-        return self.cb["getContacts"](unicode(profile_key))
+        return self._callback("getContacts", unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssi', out_signature='a{i(ss)}',
                          async_callbacks=None)
     def getHistory(self, from_jid, to_jid, size):
-        return self.cb["getHistory"](unicode(from_jid), unicode(to_jid), size)
+        return self._callback("getHistory", unicode(from_jid), unicode(to_jid), size)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ss', out_signature='s',
                          async_callbacks=None)
     def getLastResource(self, contact_jid, profile_key="@DEFAULT@"):
-        return self.cb["getLastResource"](unicode(contact_jid), unicode(profile_key))
+        return self._callback("getLastResource", unicode(contact_jid), unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='sss', out_signature='s',
                          async_callbacks=None)
     def getMenuHelp(self, category, name, menu_type):
-        return self.cb["getMenuHelp"](unicode(category), unicode(name), unicode(menu_type))
+        return self._callback("getMenuHelp", unicode(category), unicode(name), unicode(menu_type))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='', out_signature='a(sss)',
                          async_callbacks=None)
     def getMenus(self, ):
-        return self.cb["getMenus"]()
+        return self._callback("getMenus", )
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssss', out_signature='s',
                          async_callbacks=None)
     def getParamA(self, name, category, attribute="value", profile_key="@DEFAULT@"):
-        return self.cb["getParamA"](unicode(name), unicode(category), unicode(attribute), unicode(profile_key))
+        return self._callback("getParamA", unicode(name), unicode(category), unicode(attribute), unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='s',
-                         async_callbacks=None)
-    def getParams(self, profile_key="@DEFAULT@"):
-        return self.cb["getParams"](unicode(profile_key))
+                         async_callbacks=('callback', 'errback'))
+    def getParams(self, profile_key="@DEFAULT@", callback=None, errback=None):
+        return self._callback("getParams", unicode(profile_key), callback=callback, errback=errback)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='', out_signature='as',
                          async_callbacks=None)
     def getParamsCategories(self, ):
-        return self.cb["getParamsCategories"]()
+        return self._callback("getParamsCategories", )
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ss', out_signature='s',
-                         async_callbacks=None)
-    def getParamsForCategory(self, category, profile_key="@DEFAULT@"):
-        return self.cb["getParamsForCategory"](unicode(category), unicode(profile_key))
+                         async_callbacks=('callback', 'errback'))
+    def getParamsForCategory(self, category, profile_key="@DEFAULT@", callback=None, errback=None):
+        return self._callback("getParamsForCategory", unicode(category), unicode(profile_key), callback=callback, errback=errback)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='s',
-                         async_callbacks=None)
-    def getParamsUI(self, profile_key="@DEFAULT@"):
-        return self.cb["getParamsUI"](unicode(profile_key))
+                         async_callbacks=('callback', 'errback'))
+    def getParamsUI(self, profile_key="@DEFAULT@", callback=None, errback=None):
+        return self._callback("getParamsUI", unicode(profile_key), callback=callback, errback=errback)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='a{sa{s(sia{ss})}}',
                          async_callbacks=None)
     def getPresenceStatus(self, profile_key="@DEFAULT@"):
-        return self.cb["getPresenceStatus"](unicode(profile_key))
+        return self._callback("getPresenceStatus", unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='s',
                          async_callbacks=None)
     def getProfileName(self, profile_key="@DEFAULT@"):
-        return self.cb["getProfileName"](unicode(profile_key))
+        return self._callback("getProfileName", unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='', out_signature='as',
                          async_callbacks=None)
     def getProfilesList(self, ):
-        return self.cb["getProfilesList"]()
+        return self._callback("getProfilesList", )
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='a{ss}',
                          async_callbacks=None)
     def getProgress(self, id):
-        return self.cb["getProgress"](unicode(id))
+        return self._callback("getProgress", unicode(id))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='', out_signature='s',
                          async_callbacks=None)
     def getVersion(self, ):
-        return self.cb["getVersion"]()
+        return self._callback("getVersion", )
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='a{ss}',
                          async_callbacks=None)
     def getWaitingSub(self, profile_key="@DEFAULT@"):
-        return self.cb["getWaitingSub"](unicode(profile_key))
+        return self._callback("getWaitingSub", unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='s', out_signature='b',
                          async_callbacks=None)
     def isConnected(self, profile_key="@DEFAULT@"):
-        return self.cb["isConnected"](unicode(profile_key))
+        return self._callback("isConnected", unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='sa{ss}s', out_signature='s',
                          async_callbacks=None)
     def launchAction(self, action_type, data, profile_key="@DEFAULT@"):
-        return self.cb["launchAction"](unicode(action_type), data, unicode(profile_key))
+        return self._callback("launchAction", unicode(action_type), data, unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssssi', out_signature='s',
                          async_callbacks=None)
     def registerNewAccount(self, login, password, email, host, port=5222):
-        return self.cb["registerNewAccount"](unicode(login), unicode(password), unicode(email), unicode(host), port)
+        return self._callback("registerNewAccount", unicode(login), unicode(password), unicode(email), unicode(host), port)
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='sssss', out_signature='',
                          async_callbacks=None)
     def sendMessage(self, to_jid, message, subject='', mess_type="chat", profile_key="@DEFAULT@"):
-        return self.cb["sendMessage"](unicode(to_jid), unicode(message), unicode(subject), unicode(mess_type), unicode(profile_key))
+        return self._callback("sendMessage", unicode(to_jid), unicode(message), unicode(subject), unicode(mess_type), unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssss', out_signature='',
                          async_callbacks=None)
     def setParam(self, name, value, category, profile_key="@DEFAULT@"):
-        return self.cb["setParam"](unicode(name), unicode(value), unicode(category), unicode(profile_key))
+        return self._callback("setParam", unicode(name), unicode(value), unicode(category), unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssia{ss}s', out_signature='',
                          async_callbacks=None)
     def setPresence(self, to_jid='', show='', priority=0, statuses={}, profile_key="@DEFAULT@"):
-        return self.cb["setPresence"](unicode(to_jid), unicode(show), priority, statuses, unicode(profile_key))
+        return self._callback("setPresence", unicode(to_jid), unicode(show), priority, statuses, unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='sss', out_signature='',
                          async_callbacks=None)
     def subscription(self, sub_type, entity, profile_key="@DEFAULT@"):
-        return self.cb["subscription"](unicode(sub_type), unicode(entity), unicode(profile_key))
+        return self._callback("subscription", unicode(sub_type), unicode(entity), unicode(profile_key))
 
     @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX,
                          in_signature='ssass', out_signature='',
                          async_callbacks=None)
     def updateContact(self, entity_jid, name, groups, profile_key="@DEFAULT@"):
-        return self.cb["updateContact"](unicode(entity_jid), unicode(name), groups, unicode(profile_key))
+        return self._callback("updateContact", unicode(entity_jid), unicode(name), groups, unicode(profile_key))
 
     
     def __attributes(self, in_sign):