# HG changeset patch # User Goffi # Date 1475522139 -7200 # Node ID 4633cfcbcccb8fc4c9990e35d30128a457d6a3ce # Parent da4097de5a9510ccf04b0bf06317eb73986326d8 bridge (D-Bus): bad design fixes: - renamed outputed module to dbus_bridge (to avoid uppercase and conflict with dbus module) - class name is now Bridge for both frontend and core (make discovery/import more easy) - register renamed to register_method in core, and register_signal in frontend diff -r da4097de5a95 -r 4633cfcbcccb frontends/src/bridge/DBus.py --- a/frontends/src/bridge/DBus.py Sun Oct 02 22:44:33 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,694 +0,0 @@ -#!/usr/bin/env python2 -#-*- coding: utf-8 -*- - -# SAT communication bridge -# Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from sat.core.i18n import _ -from bridge_frontend import BridgeFrontend, BridgeException -import dbus -from sat.core.log import getLogger -log = getLogger(__name__) -from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError - -from dbus.mainloop.glib import DBusGMainLoop -DBusGMainLoop(set_as_default=True) - -import ast - -const_INT_PREFIX = "org.goffi.SAT" # Interface prefix -const_ERROR_PREFIX = const_INT_PREFIX + ".error" -const_OBJ_PATH = '/org/goffi/SAT/bridge' -const_CORE_SUFFIX = ".core" -const_PLUGIN_SUFFIX = ".plugin" -const_TIMEOUT = 120 - - -def dbus_to_bridge_exception(dbus_e): - """Convert a DBusException to a BridgeException. - - @param dbus_e (DBusException) - @return: BridgeException - """ - full_name = dbus_e.get_dbus_name() - if full_name.startswith(const_ERROR_PREFIX): - name = dbus_e.get_dbus_name()[len(const_ERROR_PREFIX) + 1:] - else: - name = full_name - # XXX: dbus_e.args doesn't contain the original DBusException args, but we - # receive its serialized form in dbus_e.args[0]. From that we can rebuild - # the original arguments list thanks to ast.literal_eval (secure eval). - message = dbus_e.get_dbus_message() # similar to dbus_e.args[0] - try: - message, condition = ast.literal_eval(message) - except (SyntaxError, ValueError, TypeError): - condition = '' - return BridgeException(name, message, condition) - - -class DBusBridgeFrontend(BridgeFrontend): - def __init__(self): - try: - self.sessions_bus = dbus.SessionBus() - self.db_object = self.sessions_bus.get_object(const_INT_PREFIX, - const_OBJ_PATH) - self.db_core_iface = dbus.Interface(self.db_object, - dbus_interface=const_INT_PREFIX + const_CORE_SUFFIX) - self.db_plugin_iface = dbus.Interface(self.db_object, - dbus_interface=const_INT_PREFIX + const_PLUGIN_SUFFIX) - except dbus.exceptions.DBusException, e: - if e._dbus_error_name in ('org.freedesktop.DBus.Error.ServiceUnknown', - 'org.freedesktop.DBus.Error.Spawn.ExecFailed'): - raise BridgeExceptionNoService - elif e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported': - log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it")) - raise BridgeInitError - else: - raise e - #props = self.db_core_iface.getProperties() - - def register(self, functionName, handler, iface="core"): - if iface == "core": - self.db_core_iface.connect_to_signal(functionName, handler) - elif iface == "plugin": - self.db_plugin_iface.connect_to_signal(functionName, handler) - else: - log.error(_('Unknown interface')) - - def __getattribute__(self, name): - """ usual __getattribute__ if the method exists, else try to find a plugin method """ - try: - return object.__getattribute__(self, name) - except AttributeError: - # The attribute is not found, we try the plugin proxy to find the requested method - - def getPluginMethod(*args, **kwargs): - # We first check if we have an async call. We detect this in two ways: - # - if we have the 'callback' and 'errback' keyword arguments - # - or if the last two arguments are callable - - async = False - args = list(args) - - if kwargs: - if 'callback' in kwargs: - async = True - _callback = kwargs.pop('callback') - _errback = kwargs.pop('errback', lambda failure: log.error(unicode(failure))) - try: - args.append(kwargs.pop('profile')) - except KeyError: - try: - args.append(kwargs.pop('profile_key')) - except KeyError: - pass - # at this point, kwargs should be empty - if kwargs: - log.warnings(u"unexpected keyword arguments, they will be ignored: {}".format(kwargs)) - elif len(args) >= 2 and callable(args[-1]) and callable(args[-2]): - async = True - _errback = args.pop() - _callback = args.pop() - - method = getattr(self.db_plugin_iface, name) - - if async: - kwargs['timeout'] = const_TIMEOUT - kwargs['reply_handler'] = _callback - kwargs['error_handler'] = lambda err: _errback(dbus_to_bridge_exception(err)) - - return method(*args, **kwargs) - - 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 - 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.addContact(entity_jid, profile_key, **kwargs) - - def asyncConnect(self, profile_key="@DEFAULT@", password='', 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)) - return self.db_core_iface.asyncConnect(profile_key, password, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def asyncCreateProfile(self, profile, password='', 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)) - return self.db_core_iface.asyncCreateProfile(profile, password, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def asyncDeleteProfile(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)) - return self.db_core_iface.asyncDeleteProfile(profile, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def asyncGetParamA(self, name, category, attribute="value", security_limit=-1, 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)) - return unicode(self.db_core_iface.asyncGetParamA(name, category, attribute, security_limit, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)) - - def asyncGetParamsValuesFromCategory(self, category, security_limit=-1, 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)) - return self.db_core_iface.asyncGetParamsValuesFromCategory(category, security_limit, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def delContact(self, entity_jid, 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)) - return self.db_core_iface.delContact(entity_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def discoInfos(self, entity_jid, profile_key, 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)) - return self.db_core_iface.discoInfos(entity_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def discoItems(self, entity_jid, profile_key, 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)) - return self.db_core_iface.discoItems(entity_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def disconnect(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.disconnect(profile_key, **kwargs) - - def getConfig(self, section, name, 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 unicode(self.db_core_iface.getConfig(section, name, **kwargs)) - - def getContacts(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)) - return self.db_core_iface.getContacts(profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def getContactsFromGroup(self, group, 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.getContactsFromGroup(group, profile_key, **kwargs) - - def getEntitiesData(self, jids, keys, 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.getEntitiesData(jids, keys, profile, **kwargs) - - def getEntityData(self, jid, keys, 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.getEntityData(jid, keys, profile, **kwargs) - - def getFeatures(self, profile_key, 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)) - return self.db_core_iface.getFeatures(profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def getMainResource(self, contact_jid, 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 unicode(self.db_core_iface.getMainResource(contact_jid, profile_key, **kwargs)) - - def getMenuHelp(self, menu_id, language, 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 unicode(self.db_core_iface.getMenuHelp(menu_id, language, **kwargs)) - - def getMenus(self, language, security_limit, 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.getMenus(language, security_limit, **kwargs) - - def getParamA(self, name, category, attribute="value", 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 unicode(self.db_core_iface.getParamA(name, category, attribute, profile_key, **kwargs)) - - def getParamsCategories(self, 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.getParamsCategories(**kwargs) - - def getParamsUI(self, security_limit=-1, app='', 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)) - return unicode(self.db_core_iface.getParamsUI(security_limit, app, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)) - - def getPresenceStatuses(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.getPresenceStatuses(profile_key, **kwargs) - - def getProfileName(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 unicode(self.db_core_iface.getProfileName(profile_key, **kwargs)) - - def getProfilesList(self, 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.getProfilesList(**kwargs) - - def getReady(self, 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)) - return self.db_core_iface.getReady(timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def getVersion(self, 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 unicode(self.db_core_iface.getVersion(**kwargs)) - - def getWaitingSub(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.getWaitingSub(profile_key, **kwargs) - - def historyGet(self, from_jid, to_jid, limit, between=True, filters='', profile="@NONE@", 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)) - return self.db_core_iface.historyGet(from_jid, to_jid, limit, between, filters, profile, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def isConnected(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.isConnected(profile_key, **kwargs) - - def launchAction(self, callback_id, data, 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)) - return self.db_core_iface.launchAction(callback_id, data, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def loadParamsTemplate(self, filename, 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.loadParamsTemplate(filename, **kwargs) - - def messageSend(self, to_jid, message, subject={}, mess_type="auto", extra={}, profile_key="@NONE@", 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)) - return self.db_core_iface.messageSend(to_jid, message, subject, mess_type, extra, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - def paramsRegisterApp(self, xml, security_limit=-1, app='', 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.paramsRegisterApp(xml, security_limit, app, **kwargs) - - def profileIsSessionStarted(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.profileIsSessionStarted(profile_key, **kwargs) - - def profileSetDefault(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.profileSetDefault(profile, **kwargs) - - def profileStartSession(self, password='', 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)) - return self.db_core_iface.profileStartSession(password, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) - - 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 progressGetAllMetadata(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.progressGetAllMetadata(profile, **kwargs) - - def saveParamsTemplate(self, filename, 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.saveParamsTemplate(filename, **kwargs) - - def setParam(self, name, value, category, security_limit=-1, 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.setParam(name, value, category, security_limit, profile_key, **kwargs) - - def setPresence(self, to_jid='', show='', statuses={}, 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.setPresence(to_jid, show, statuses, profile_key, **kwargs) - - def subscription(self, sub_type, entity, 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.subscription(sub_type, entity, profile_key, **kwargs) - - def updateContact(self, entity_jid, name, groups, 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)) - return self.db_core_iface.updateContact(entity_jid, name, groups, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) diff -r da4097de5a95 -r 4633cfcbcccb frontends/src/bridge/dbus_bridge.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/frontends/src/bridge/dbus_bridge.py Mon Oct 03 21:15:39 2016 +0200 @@ -0,0 +1,694 @@ +#!/usr/bin/env python2 +#-*- coding: utf-8 -*- + +# SAT communication bridge +# Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from sat.core.i18n import _ +from bridge_frontend import BridgeFrontend, BridgeException +import dbus +from sat.core.log import getLogger +log = getLogger(__name__) +from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError + +from dbus.mainloop.glib import DBusGMainLoop +DBusGMainLoop(set_as_default=True) + +import ast + +const_INT_PREFIX = "org.goffi.SAT" # Interface prefix +const_ERROR_PREFIX = const_INT_PREFIX + ".error" +const_OBJ_PATH = '/org/goffi/SAT/bridge' +const_CORE_SUFFIX = ".core" +const_PLUGIN_SUFFIX = ".plugin" +const_TIMEOUT = 120 + + +def dbus_to_bridge_exception(dbus_e): + """Convert a DBusException to a BridgeException. + + @param dbus_e (DBusException) + @return: BridgeException + """ + full_name = dbus_e.get_dbus_name() + if full_name.startswith(const_ERROR_PREFIX): + name = dbus_e.get_dbus_name()[len(const_ERROR_PREFIX) + 1:] + else: + name = full_name + # XXX: dbus_e.args doesn't contain the original DBusException args, but we + # receive its serialized form in dbus_e.args[0]. From that we can rebuild + # the original arguments list thanks to ast.literal_eval (secure eval). + message = dbus_e.get_dbus_message() # similar to dbus_e.args[0] + try: + message, condition = ast.literal_eval(message) + except (SyntaxError, ValueError, TypeError): + condition = '' + return BridgeException(name, message, condition) + + +class Bridge(BridgeFrontend): + def __init__(self): + try: + self.sessions_bus = dbus.SessionBus() + self.db_object = self.sessions_bus.get_object(const_INT_PREFIX, + const_OBJ_PATH) + self.db_core_iface = dbus.Interface(self.db_object, + dbus_interface=const_INT_PREFIX + const_CORE_SUFFIX) + self.db_plugin_iface = dbus.Interface(self.db_object, + dbus_interface=const_INT_PREFIX + const_PLUGIN_SUFFIX) + except dbus.exceptions.DBusException, e: + if e._dbus_error_name in ('org.freedesktop.DBus.Error.ServiceUnknown', + 'org.freedesktop.DBus.Error.Spawn.ExecFailed'): + raise BridgeExceptionNoService + elif e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported': + log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it")) + raise BridgeInitError + else: + raise e + #props = self.db_core_iface.getProperties() + + def register_signal(self, functionName, handler, iface="core"): + if iface == "core": + self.db_core_iface.connect_to_signal(functionName, handler) + elif iface == "plugin": + self.db_plugin_iface.connect_to_signal(functionName, handler) + else: + log.error(_('Unknown interface')) + + def __getattribute__(self, name): + """ usual __getattribute__ if the method exists, else try to find a plugin method """ + try: + return object.__getattribute__(self, name) + except AttributeError: + # The attribute is not found, we try the plugin proxy to find the requested method + + def getPluginMethod(*args, **kwargs): + # We first check if we have an async call. We detect this in two ways: + # - if we have the 'callback' and 'errback' keyword arguments + # - or if the last two arguments are callable + + async = False + args = list(args) + + if kwargs: + if 'callback' in kwargs: + async = True + _callback = kwargs.pop('callback') + _errback = kwargs.pop('errback', lambda failure: log.error(unicode(failure))) + try: + args.append(kwargs.pop('profile')) + except KeyError: + try: + args.append(kwargs.pop('profile_key')) + except KeyError: + pass + # at this point, kwargs should be empty + if kwargs: + log.warnings(u"unexpected keyword arguments, they will be ignored: {}".format(kwargs)) + elif len(args) >= 2 and callable(args[-1]) and callable(args[-2]): + async = True + _errback = args.pop() + _callback = args.pop() + + method = getattr(self.db_plugin_iface, name) + + if async: + kwargs['timeout'] = const_TIMEOUT + kwargs['reply_handler'] = _callback + kwargs['error_handler'] = lambda err: _errback(dbus_to_bridge_exception(err)) + + return method(*args, **kwargs) + + 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 + 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.addContact(entity_jid, profile_key, **kwargs) + + def asyncConnect(self, profile_key="@DEFAULT@", password='', 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)) + return self.db_core_iface.asyncConnect(profile_key, password, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def asyncCreateProfile(self, profile, password='', 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)) + return self.db_core_iface.asyncCreateProfile(profile, password, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def asyncDeleteProfile(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)) + return self.db_core_iface.asyncDeleteProfile(profile, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def asyncGetParamA(self, name, category, attribute="value", security_limit=-1, 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)) + return unicode(self.db_core_iface.asyncGetParamA(name, category, attribute, security_limit, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)) + + def asyncGetParamsValuesFromCategory(self, category, security_limit=-1, 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)) + return self.db_core_iface.asyncGetParamsValuesFromCategory(category, security_limit, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def delContact(self, entity_jid, 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)) + return self.db_core_iface.delContact(entity_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def discoInfos(self, entity_jid, profile_key, 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)) + return self.db_core_iface.discoInfos(entity_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def discoItems(self, entity_jid, profile_key, 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)) + return self.db_core_iface.discoItems(entity_jid, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def disconnect(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.disconnect(profile_key, **kwargs) + + def getConfig(self, section, name, 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 unicode(self.db_core_iface.getConfig(section, name, **kwargs)) + + def getContacts(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)) + return self.db_core_iface.getContacts(profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def getContactsFromGroup(self, group, 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.getContactsFromGroup(group, profile_key, **kwargs) + + def getEntitiesData(self, jids, keys, 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.getEntitiesData(jids, keys, profile, **kwargs) + + def getEntityData(self, jid, keys, 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.getEntityData(jid, keys, profile, **kwargs) + + def getFeatures(self, profile_key, 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)) + return self.db_core_iface.getFeatures(profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def getMainResource(self, contact_jid, 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 unicode(self.db_core_iface.getMainResource(contact_jid, profile_key, **kwargs)) + + def getMenuHelp(self, menu_id, language, 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 unicode(self.db_core_iface.getMenuHelp(menu_id, language, **kwargs)) + + def getMenus(self, language, security_limit, 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.getMenus(language, security_limit, **kwargs) + + def getParamA(self, name, category, attribute="value", 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 unicode(self.db_core_iface.getParamA(name, category, attribute, profile_key, **kwargs)) + + def getParamsCategories(self, 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.getParamsCategories(**kwargs) + + def getParamsUI(self, security_limit=-1, app='', 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)) + return unicode(self.db_core_iface.getParamsUI(security_limit, app, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)) + + def getPresenceStatuses(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.getPresenceStatuses(profile_key, **kwargs) + + def getProfileName(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 unicode(self.db_core_iface.getProfileName(profile_key, **kwargs)) + + def getProfilesList(self, 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.getProfilesList(**kwargs) + + def getReady(self, 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)) + return self.db_core_iface.getReady(timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def getVersion(self, 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 unicode(self.db_core_iface.getVersion(**kwargs)) + + def getWaitingSub(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.getWaitingSub(profile_key, **kwargs) + + def historyGet(self, from_jid, to_jid, limit, between=True, filters='', profile="@NONE@", 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)) + return self.db_core_iface.historyGet(from_jid, to_jid, limit, between, filters, profile, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def isConnected(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.isConnected(profile_key, **kwargs) + + def launchAction(self, callback_id, data, 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)) + return self.db_core_iface.launchAction(callback_id, data, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def loadParamsTemplate(self, filename, 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.loadParamsTemplate(filename, **kwargs) + + def messageSend(self, to_jid, message, subject={}, mess_type="auto", extra={}, profile_key="@NONE@", 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)) + return self.db_core_iface.messageSend(to_jid, message, subject, mess_type, extra, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + def paramsRegisterApp(self, xml, security_limit=-1, app='', 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.paramsRegisterApp(xml, security_limit, app, **kwargs) + + def profileIsSessionStarted(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.profileIsSessionStarted(profile_key, **kwargs) + + def profileSetDefault(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.profileSetDefault(profile, **kwargs) + + def profileStartSession(self, password='', 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)) + return self.db_core_iface.profileStartSession(password, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) + + 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 progressGetAllMetadata(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.progressGetAllMetadata(profile, **kwargs) + + def saveParamsTemplate(self, filename, 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.saveParamsTemplate(filename, **kwargs) + + def setParam(self, name, value, category, security_limit=-1, 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.setParam(name, value, category, security_limit, profile_key, **kwargs) + + def setPresence(self, to_jid='', show='', statuses={}, 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.setPresence(to_jid, show, statuses, profile_key, **kwargs) + + def subscription(self, sub_type, entity, 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.subscription(sub_type, entity, profile_key, **kwargs) + + def updateContact(self, entity_jid, name, groups, 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)) + return self.db_core_iface.updateContact(entity_jid, name, groups, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler) diff -r da4097de5a95 -r 4633cfcbcccb frontends/src/jp/base.py --- a/frontends/src/jp/base.py Sun Oct 02 22:44:33 2016 +0200 +++ b/frontends/src/jp/base.py Mon Oct 03 21:15:39 2016 +0200 @@ -33,7 +33,7 @@ from glob import iglob from importlib import import_module from sat_frontends.tools.jid import JID -from sat_frontends.bridge.DBus import DBusBridgeFrontend +from sat_frontends.bridge.dbus_bridge import Bridge from sat.core import exceptions import sat_frontends.jp from sat_frontends.jp.constants import Const as C @@ -96,7 +96,7 @@ by default display a message """ try: - self.bridge = DBusBridgeFrontend() + self.bridge = Bridge() except exceptions.BridgeExceptionNoService: print(_(u"Can't connect to SàT backend, are you sure it's launched ?")) sys.exit(1) diff -r da4097de5a95 -r 4633cfcbcccb frontends/src/primitivus/primitivus --- a/frontends/src/primitivus/primitivus Sun Oct 02 22:44:33 2016 +0200 +++ b/frontends/src/primitivus/primitivus Mon Oct 03 21:15:39 2016 +0200 @@ -28,7 +28,7 @@ import urwid from urwid.util import is_wide_char from urwid_satext import sat_widgets -from sat_frontends.bridge.DBus import DBusBridgeFrontend +from sat_frontends.bridge.dbus_bridge import Bridge from sat_frontends.quick_frontend.quick_app import QuickApp from sat_frontends.quick_frontend import quick_utils from sat_frontends.quick_frontend import quick_chat @@ -276,7 +276,7 @@ AVATAR_HANDLER = False def __init__(self): - QuickApp.__init__(self, create_bridge=DBusBridgeFrontend, xmlui=xmlui, check_options=quick_utils.check_options) + QuickApp.__init__(self, create_bridge=Bridge, xmlui=xmlui, check_options=quick_utils.check_options) ## main loop setup ## self.main_widget = ProfileManager(self) diff -r da4097de5a95 -r 4633cfcbcccb frontends/src/quick_frontend/quick_app.py --- a/frontends/src/quick_frontend/quick_app.py Sun Oct 02 22:44:33 2016 +0200 +++ b/frontends/src/quick_frontend/quick_app.py Mon Oct 03 21:15:39 2016 +0200 @@ -287,7 +287,7 @@ if handler is None: handler = getattr(self, "{}{}".format(function_name, 'Handler')) if not with_profile: - self.bridge.register(function_name, handler, iface) + self.bridge.register_signal(function_name, handler, iface) return def signalReceived(*args, **kwargs): @@ -303,7 +303,7 @@ self.signals_cache.setdefault(profile, []).append((function_name, handler, args, kwargs)) return # we ignore signal for profiles we don't manage handler(*args, **kwargs) - self.bridge.register(function_name, signalReceived, iface) + self.bridge.register_signal(function_name, signalReceived, iface) def addListener(self, type_, callback, profiles_filter=None): """Add a listener for an event diff -r da4097de5a95 -r 4633cfcbcccb src/bridge/DBus.py --- a/src/bridge/DBus.py Sun Oct 02 22:44:33 2016 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,623 +0,0 @@ -#!/usr/bin/env python2 -#-*- coding: utf-8 -*- - -# SAT: a jabber client -# Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org) - -# This program is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. - -# You should have received a copy of the GNU Affero General Public License -# along with this program. If not, see . - -from sat.core.i18n import _ -import dbus -import dbus.service -import dbus.mainloop.glib -import inspect -from sat.core.log import getLogger -log = getLogger(__name__) -from twisted.internet.defer import Deferred -from sat.core.exceptions import BridgeInitError - -const_INT_PREFIX = "org.goffi.SAT" # Interface prefix -const_ERROR_PREFIX = const_INT_PREFIX + ".error" -const_OBJ_PATH = '/org/goffi/SAT/bridge' -const_CORE_SUFFIX = ".core" -const_PLUGIN_SUFFIX = ".plugin" - - -class ParseError(Exception): - pass - - -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 DeferredNotAsync(dbus.DBusException): - _dbus_error_name = const_ERROR_PREFIX + ".DeferredNotAsync" - - -class GenericException(dbus.DBusException): - def __init__(self, twisted_error): - """ - - @param twisted_error (Failure): instance of twisted Failure - @return: DBusException - """ - super(GenericException, self).__init__() - try: - # twisted_error.value is a class - class_ = twisted_error.value().__class__ - except TypeError: - # twisted_error.value is an instance - class_ = twisted_error.value.__class__ - message = twisted_error.getErrorMessage() - try: - self.args = (message, twisted_error.value.condition) - except AttributeError: - self.args = (message,) - self._dbus_error_name = '.'.join([const_ERROR_PREFIX, class_.__module__, class_.__name__]) - - -class DbusObject(dbus.service.Object): - - def __init__(self, bus, path): - dbus.service.Object.__init__(self, bus, path) - log.debug("Init DbusObject...") - self.cb = {} - - 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: - log.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): - log.error("Asynchronous method [%s] does not return a Deferred." % name) - raise AsyncNotDeferred - result.addCallback(lambda result: callback() if result is None else callback(result)) - result.addErrback(lambda err: errback(GenericException(err))) - else: - if isinstance(result, Deferred): - log.error("Synchronous method [%s] return a Deferred." % name) - raise DeferredNotAsync - return result - ### signals ### - - @dbus.service.signal(const_INT_PREFIX + const_PLUGIN_SUFFIX, - signature='') - def dummySignal(self): - #FIXME: workaround for addSignal (doesn't work if one method doensn't - # already exist for plugins), probably missing some initialisation, need - # further investigations - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='a{ss}sis') - def actionNew(self, action_data, id, security_limit, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='ss') - def connected(self, profile, jid_s): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='ss') - def contactDeleted(self, entity_jid, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='s') - def disconnected(self, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='ssss') - def entityDataUpdated(self, jid, name, value, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='sdssa{ss}a{ss}sa{ss}s') - def messageNew(self, uid, timestamp, from_jid, to_jid, message, subject, mess_type, extra, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='sa{ss}ass') - def newContact(self, contact_jid, attributes, groups, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='ssss') - def paramUpdate(self, name, value, category, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='ssia{ss}s') - def presenceUpdate(self, entity_jid, show, priority, statuses, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='sss') - def progressError(self, id, error, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='sa{ss}s') - def progressFinished(self, id, metadata, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='sa{ss}s') - def progressStarted(self, id, metadata, profile): - pass - - @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, - signature='sss') - def subscribe(self, sub_type, entity_jid, profile): - pass - - ### 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@"): - return self._callback("addContact", unicode(entity_jid), unicode(profile_key)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='b', - async_callbacks=('callback', 'errback')) - def asyncConnect(self, profile_key="@DEFAULT@", password='', callback=None, errback=None): - return self._callback("asyncConnect", unicode(profile_key), unicode(password), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='', - async_callbacks=('callback', 'errback')) - def asyncCreateProfile(self, profile, password='', callback=None, errback=None): - return self._callback("asyncCreateProfile", unicode(profile), unicode(password), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='s', out_signature='', - async_callbacks=('callback', 'errback')) - def asyncDeleteProfile(self, profile, callback=None, errback=None): - return self._callback("asyncDeleteProfile", unicode(profile), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='sssis', out_signature='s', - async_callbacks=('callback', 'errback')) - def asyncGetParamA(self, name, category, attribute="value", security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("asyncGetParamA", unicode(name), unicode(category), unicode(attribute), security_limit, unicode(profile_key), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='sis', out_signature='a{ss}', - async_callbacks=('callback', 'errback')) - def asyncGetParamsValuesFromCategory(self, category, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("asyncGetParamsValuesFromCategory", unicode(category), security_limit, unicode(profile_key), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='', - async_callbacks=('callback', 'errback')) - def delContact(self, entity_jid, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("delContact", unicode(entity_jid), unicode(profile_key), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='(asa(sss)a{sa(a{ss}as)})', - async_callbacks=('callback', 'errback')) - def discoInfos(self, entity_jid, profile_key, callback=None, errback=None): - return self._callback("discoInfos", unicode(entity_jid), unicode(profile_key), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='a(sss)', - async_callbacks=('callback', 'errback')) - def discoItems(self, entity_jid, profile_key, callback=None, errback=None): - return self._callback("discoItems", unicode(entity_jid), unicode(profile_key), callback=callback, errback=errback) - - @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._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._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=('callback', 'errback')) - def getContacts(self, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("getContacts", unicode(profile_key), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='as', - async_callbacks=None) - def getContactsFromGroup(self, group, profile_key="@DEFAULT@"): - return self._callback("getContactsFromGroup", unicode(group), unicode(profile_key)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='asass', out_signature='a{sa{ss}}', - async_callbacks=None) - def getEntitiesData(self, jids, keys, profile): - return self._callback("getEntitiesData", jids, keys, unicode(profile)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='sass', out_signature='a{ss}', - async_callbacks=None) - def getEntityData(self, jid, keys, profile): - return self._callback("getEntityData", unicode(jid), keys, unicode(profile)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='s', out_signature='a{sa{ss}}', - async_callbacks=('callback', 'errback')) - def getFeatures(self, profile_key, callback=None, errback=None): - return self._callback("getFeatures", unicode(profile_key), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='s', - async_callbacks=None) - def getMainResource(self, contact_jid, profile_key="@DEFAULT@"): - return self._callback("getMainResource", unicode(contact_jid), unicode(profile_key)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='s', - async_callbacks=None) - def getMenuHelp(self, menu_id, language): - return self._callback("getMenuHelp", unicode(menu_id), unicode(language)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='si', out_signature='a(ssasasa{ss})', - async_callbacks=None) - def getMenus(self, language, security_limit): - return self._callback("getMenus", unicode(language), security_limit) - - @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._callback("getParamA", unicode(name), unicode(category), unicode(attribute), unicode(profile_key)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='', out_signature='as', - async_callbacks=None) - def getParamsCategories(self, ): - return self._callback("getParamsCategories", ) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='iss', out_signature='s', - async_callbacks=('callback', 'errback')) - def getParamsUI(self, security_limit=-1, app='', profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("getParamsUI", security_limit, unicode(app), 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 getPresenceStatuses(self, profile_key="@DEFAULT@"): - return self._callback("getPresenceStatuses", 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._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._callback("getProfilesList", ) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='', out_signature='', - async_callbacks=('callback', 'errback')) - def getReady(self, callback=None, errback=None): - return self._callback("getReady", callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='', out_signature='s', - async_callbacks=None) - def getVersion(self, ): - 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._callback("getWaitingSub", unicode(profile_key)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ssiba{ss}s', out_signature='a(sdssa{ss}a{ss}sa{ss})', - async_callbacks=('callback', 'errback')) - def historyGet(self, from_jid, to_jid, limit, between=True, filters='', profile="@NONE@", callback=None, errback=None): - return self._callback("historyGet", unicode(from_jid), unicode(to_jid), limit, between, filters, unicode(profile), callback=callback, errback=errback) - - @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._callback("isConnected", unicode(profile_key)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='sa{ss}s', out_signature='a{ss}', - async_callbacks=('callback', 'errback')) - def launchAction(self, callback_id, data, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("launchAction", unicode(callback_id), data, unicode(profile_key), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='s', out_signature='b', - async_callbacks=None) - def loadParamsTemplate(self, filename): - return self._callback("loadParamsTemplate", unicode(filename)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='sa{ss}a{ss}sa{ss}s', out_signature='', - async_callbacks=('callback', 'errback')) - def messageSend(self, to_jid, message, subject={}, mess_type="auto", extra={}, profile_key="@NONE@", callback=None, errback=None): - return self._callback("messageSend", unicode(to_jid), message, subject, unicode(mess_type), extra, unicode(profile_key), callback=callback, errback=errback) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='sis', out_signature='', - async_callbacks=None) - def paramsRegisterApp(self, xml, security_limit=-1, app=''): - return self._callback("paramsRegisterApp", unicode(xml), security_limit, unicode(app)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='s', out_signature='b', - async_callbacks=None) - def profileIsSessionStarted(self, profile_key="@DEFAULT@"): - return self._callback("profileIsSessionStarted", unicode(profile_key)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='s', out_signature='', - async_callbacks=None) - def profileSetDefault(self, profile): - return self._callback("profileSetDefault", unicode(profile)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ss', out_signature='b', - async_callbacks=('callback', 'errback')) - def profileStartSession(self, password='', profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("profileStartSession", unicode(password), unicode(profile_key), callback=callback, errback=errback) - - @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='a{sa{sa{ss}}}', - async_callbacks=None) - def progressGetAllMetadata(self, profile): - return self._callback("progressGetAllMetadata", unicode(profile)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='s', out_signature='b', - async_callbacks=None) - def saveParamsTemplate(self, filename): - return self._callback("saveParamsTemplate", unicode(filename)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='sssis', out_signature='', - async_callbacks=None) - def setParam(self, name, value, category, security_limit=-1, profile_key="@DEFAULT@"): - return self._callback("setParam", unicode(name), unicode(value), unicode(category), security_limit, unicode(profile_key)) - - @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, - in_signature='ssa{ss}s', out_signature='', - async_callbacks=None) - def setPresence(self, to_jid='', show='', statuses={}, profile_key="@DEFAULT@"): - return self._callback("setPresence", unicode(to_jid), unicode(show), 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._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=('callback', 'errback')) - def updateContact(self, entity_jid, name, groups, profile_key="@DEFAULT@", callback=None, errback=None): - return self._callback("updateContact", unicode(entity_jid), unicode(name), groups, unicode(profile_key), callback=callback, errback=errback) - - def __attributes(self, in_sign): - """Return arguments to user given a in_sign - @param in_sign: in_sign in the short form (using s,a,i,b etc) - @return: list of arguments that correspond to a in_sign (e.g.: "sss" return "arg1, arg2, arg3")""" - i = 0 - idx = 0 - attr = [] - while i < len(in_sign): - if in_sign[i] not in ['b', 'y', 'n', 'i', 'x', 'q', 'u', 't', 'd', 's', 'a']: - raise ParseError("Unmanaged attribute type [%c]" % in_sign[i]) - - attr.append("arg_%i" % idx) - idx += 1 - - if in_sign[i] == 'a': - i += 1 - if in_sign[i] != '{' and in_sign[i] != '(': # FIXME: must manage tuples out of arrays - i += 1 - continue # we have a simple type for the array - opening_car = in_sign[i] - assert(opening_car in ['{', '(']) - closing_car = '}' if opening_car == '{' else ')' - opening_count = 1 - while (True): # we have a dict or a list of tuples - i += 1 - if i >= len(in_sign): - raise ParseError("missing }") - if in_sign[i] == opening_car: - opening_count += 1 - if in_sign[i] == closing_car: - opening_count -= 1 - if opening_count == 0: - break - i += 1 - return attr - - def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False): - """Dynamically add a method to Dbus Bridge""" - inspect_args = inspect.getargspec(method) - - _arguments = inspect_args.args - _defaults = list(inspect_args.defaults or []) - - if inspect.ismethod(method): - #if we have a method, we don't want the first argument (usually 'self') - del(_arguments[0]) - - #first arguments are for the _callback method - arguments_callback = ', '.join([repr(name)] + ((_arguments + ['callback=callback', 'errback=errback']) if async else _arguments)) - - if async: - _arguments.extend(['callback', 'errback']) - _defaults.extend([None, None]) - - #now we create a second list with default values - for i in range(1, len(_defaults) + 1): - _arguments[-i] = "%s = %s" % (_arguments[-i], repr(_defaults[-i])) - - arguments_defaults = ', '.join(_arguments) - - code = compile('def %(name)s (self,%(arguments_defaults)s): return self._callback(%(arguments_callback)s)' % - {'name': name, 'arguments_defaults': arguments_defaults, 'arguments_callback': arguments_callback}, '', 'exec') - exec (code) # FIXME: to the same thing in a cleaner way, without compile/exec - method = locals()[name] - async_callbacks = ('callback', 'errback') if async else None - setattr(DbusObject, name, dbus.service.method( - const_INT_PREFIX + int_suffix, in_signature=in_sign, out_signature=out_sign, - async_callbacks=async_callbacks)(method)) - function = getattr(self, name) - func_table = self._dbus_class_table[self.__class__.__module__ + '.' + self.__class__.__name__][function._dbus_interface] - func_table[function.__name__] = function # Needed for introspection - - def addSignal(self, name, int_suffix, signature, doc={}): - """Dynamically add a signal to Dbus Bridge""" - attributes = ', '.join(self.__attributes(signature)) - #TODO: use doc parameter to name attributes - - #code = compile ('def '+name+' (self,'+attributes+'): log.debug ("'+name+' signal")', '','exec') #XXX: the log.debug is too annoying with xmllog - code = compile('def ' + name + ' (self,' + attributes + '): pass', '', 'exec') - exec (code) - signal = locals()[name] - setattr(DbusObject, name, dbus.service.signal( - const_INT_PREFIX + int_suffix, signature=signature)(signal)) - function = getattr(self, name) - func_table = self._dbus_class_table[self.__class__.__module__ + '.' + self.__class__.__name__][function._dbus_interface] - func_table[function.__name__] = function # Needed for introspection - - -class DBusBridge(object): - def __init__(self): - dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) - log.info("Init DBus...") - try: - self.session_bus = dbus.SessionBus() - except dbus.DBusException as e: - if e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported': - log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it")) - raise BridgeInitError - self.dbus_name = dbus.service.BusName(const_INT_PREFIX, self.session_bus) - self.dbus_bridge = DbusObject(self.session_bus, const_OBJ_PATH) - - def actionNew(self, action_data, id, security_limit, profile): - self.dbus_bridge.actionNew(action_data, id, security_limit, profile) - - def connected(self, profile, jid_s): - self.dbus_bridge.connected(profile, jid_s) - - def contactDeleted(self, entity_jid, profile): - self.dbus_bridge.contactDeleted(entity_jid, profile) - - def disconnected(self, profile): - self.dbus_bridge.disconnected(profile) - - def entityDataUpdated(self, jid, name, value, profile): - self.dbus_bridge.entityDataUpdated(jid, name, value, profile) - - def messageNew(self, uid, timestamp, from_jid, to_jid, message, subject, mess_type, extra, profile): - self.dbus_bridge.messageNew(uid, timestamp, from_jid, to_jid, message, subject, mess_type, extra, profile) - - def newContact(self, contact_jid, attributes, groups, profile): - self.dbus_bridge.newContact(contact_jid, attributes, groups, profile) - - def paramUpdate(self, name, value, category, profile): - self.dbus_bridge.paramUpdate(name, value, category, profile) - - def presenceUpdate(self, entity_jid, show, priority, statuses, profile): - self.dbus_bridge.presenceUpdate(entity_jid, show, priority, statuses, profile) - - def progressError(self, id, error, profile): - self.dbus_bridge.progressError(id, error, profile) - - def progressFinished(self, id, metadata, profile): - self.dbus_bridge.progressFinished(id, metadata, profile) - - def progressStarted(self, id, metadata, profile): - self.dbus_bridge.progressStarted(id, metadata, profile) - - def subscribe(self, sub_type, entity_jid, profile): - self.dbus_bridge.subscribe(sub_type, entity_jid, profile) - - def register(self, name, callback): - log.debug("registering DBus bridge method [%s]" % name) - self.dbus_bridge.register(name, callback) - - def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): - """Dynamically add a method to Dbus Bridge""" - #FIXME: doc parameter is kept only temporary, the time to remove it from calls - log.debug("Adding method [%s] to DBus bridge" % name) - self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async) - self.register(name, method) - - def addSignal(self, name, int_suffix, signature, doc={}): - self.dbus_bridge.addSignal(name, int_suffix, signature, doc) - setattr(DBusBridge, name, getattr(self.dbus_bridge, name)) \ No newline at end of file diff -r da4097de5a95 -r 4633cfcbcccb src/bridge/bridge_constructor/constructors/dbus/constructor.py --- a/src/bridge/bridge_constructor/constructors/dbus/constructor.py Sun Oct 02 22:44:33 2016 +0200 +++ b/src/bridge/bridge_constructor/constructors/dbus/constructor.py Mon Oct 03 21:15:39 2016 +0200 @@ -23,7 +23,7 @@ class DbusConstructor(base_constructor.Constructor): NAME = "dbus" CORE_TEMPLATE = "dbus_core_template.py" - CORE_DEST = "DBus.py" + CORE_DEST = "dbus_bridge.py" CORE_FORMATS = { 'signals': """\ @dbus.service.signal(const_INT_PREFIX+const_{category}_SUFFIX, diff -r da4097de5a95 -r 4633cfcbcccb src/bridge/bridge_constructor/constructors/dbus/dbus_core_template.py --- a/src/bridge/bridge_constructor/constructors/dbus/dbus_core_template.py Sun Oct 02 22:44:33 2016 +0200 +++ b/src/bridge/bridge_constructor/constructors/dbus/dbus_core_template.py Mon Oct 03 21:15:39 2016 +0200 @@ -83,7 +83,7 @@ log.debug("Init DbusObject...") self.cb = {} - def register(self, name, cb): + def register_method(self, name, cb): self.cb[name] = cb def _callback(self, name, *args, **kwargs): @@ -216,7 +216,7 @@ func_table[function.__name__] = function # Needed for introspection -class DBusBridge(object): +class Bridge(object): def __init__(self): dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) log.info("Init DBus...") @@ -230,17 +230,17 @@ self.dbus_bridge = DbusObject(self.session_bus, const_OBJ_PATH) ##SIGNAL_DIRECT_CALLS_PART## - def register(self, name, callback): + def register_method(self, name, callback): log.debug("registering DBus bridge method [%s]" % name) - self.dbus_bridge.register(name, callback) + self.dbus_bridge.register_method(name, callback) def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): """Dynamically add a method to Dbus Bridge""" #FIXME: doc parameter is kept only temporary, the time to remove it from calls log.debug("Adding method [%s] to DBus bridge" % name) self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async) - self.register(name, method) + self.register_method(name, method) def addSignal(self, name, int_suffix, signature, doc={}): self.dbus_bridge.addSignal(name, int_suffix, signature, doc) - setattr(DBusBridge, name, getattr(self.dbus_bridge, name)) + setattr(Bridge, name, getattr(self.dbus_bridge, name)) diff -r da4097de5a95 -r 4633cfcbcccb src/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py --- a/src/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py Sun Oct 02 22:44:33 2016 +0200 +++ b/src/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py Mon Oct 03 21:15:39 2016 +0200 @@ -59,7 +59,7 @@ return BridgeException(name, message, condition) -class DBusBridgeFrontend(BridgeFrontend): +class Bridge(BridgeFrontend): def __init__(self): try: self.sessions_bus = dbus.SessionBus() @@ -80,7 +80,7 @@ raise e #props = self.db_core_iface.getProperties() - def register(self, functionName, handler, iface="core"): + def register_signal(self, functionName, handler, iface="core"): if iface == "core": self.db_core_iface.connect_to_signal(functionName, handler) elif iface == "plugin": diff -r da4097de5a95 -r 4633cfcbcccb src/bridge/dbus_bridge.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/bridge/dbus_bridge.py Mon Oct 03 21:15:39 2016 +0200 @@ -0,0 +1,623 @@ +#!/usr/bin/env python2 +#-*- coding: utf-8 -*- + +# SAT: a jabber client +# Copyright (C) 2009-2016 Jérôme Poisson (goffi@goffi.org) + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. + +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . + +from sat.core.i18n import _ +import dbus +import dbus.service +import dbus.mainloop.glib +import inspect +from sat.core.log import getLogger +log = getLogger(__name__) +from twisted.internet.defer import Deferred +from sat.core.exceptions import BridgeInitError + +const_INT_PREFIX = "org.goffi.SAT" # Interface prefix +const_ERROR_PREFIX = const_INT_PREFIX + ".error" +const_OBJ_PATH = '/org/goffi/SAT/bridge' +const_CORE_SUFFIX = ".core" +const_PLUGIN_SUFFIX = ".plugin" + + +class ParseError(Exception): + pass + + +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 DeferredNotAsync(dbus.DBusException): + _dbus_error_name = const_ERROR_PREFIX + ".DeferredNotAsync" + + +class GenericException(dbus.DBusException): + def __init__(self, twisted_error): + """ + + @param twisted_error (Failure): instance of twisted Failure + @return: DBusException + """ + super(GenericException, self).__init__() + try: + # twisted_error.value is a class + class_ = twisted_error.value().__class__ + except TypeError: + # twisted_error.value is an instance + class_ = twisted_error.value.__class__ + message = twisted_error.getErrorMessage() + try: + self.args = (message, twisted_error.value.condition) + except AttributeError: + self.args = (message,) + self._dbus_error_name = '.'.join([const_ERROR_PREFIX, class_.__module__, class_.__name__]) + + +class DbusObject(dbus.service.Object): + + def __init__(self, bus, path): + dbus.service.Object.__init__(self, bus, path) + log.debug("Init DbusObject...") + self.cb = {} + + def register_method(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: + log.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): + log.error("Asynchronous method [%s] does not return a Deferred." % name) + raise AsyncNotDeferred + result.addCallback(lambda result: callback() if result is None else callback(result)) + result.addErrback(lambda err: errback(GenericException(err))) + else: + if isinstance(result, Deferred): + log.error("Synchronous method [%s] return a Deferred." % name) + raise DeferredNotAsync + return result + ### signals ### + + @dbus.service.signal(const_INT_PREFIX + const_PLUGIN_SUFFIX, + signature='') + def dummySignal(self): + #FIXME: workaround for addSignal (doesn't work if one method doensn't + # already exist for plugins), probably missing some initialisation, need + # further investigations + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='a{ss}sis') + def actionNew(self, action_data, id, security_limit, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='ss') + def connected(self, profile, jid_s): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='ss') + def contactDeleted(self, entity_jid, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='s') + def disconnected(self, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='ssss') + def entityDataUpdated(self, jid, name, value, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='sdssa{ss}a{ss}sa{ss}s') + def messageNew(self, uid, timestamp, from_jid, to_jid, message, subject, mess_type, extra, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='sa{ss}ass') + def newContact(self, contact_jid, attributes, groups, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='ssss') + def paramUpdate(self, name, value, category, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='ssia{ss}s') + def presenceUpdate(self, entity_jid, show, priority, statuses, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='sss') + def progressError(self, id, error, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='sa{ss}s') + def progressFinished(self, id, metadata, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='sa{ss}s') + def progressStarted(self, id, metadata, profile): + pass + + @dbus.service.signal(const_INT_PREFIX+const_CORE_SUFFIX, + signature='sss') + def subscribe(self, sub_type, entity_jid, profile): + pass + + ### 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@"): + return self._callback("addContact", unicode(entity_jid), unicode(profile_key)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='b', + async_callbacks=('callback', 'errback')) + def asyncConnect(self, profile_key="@DEFAULT@", password='', callback=None, errback=None): + return self._callback("asyncConnect", unicode(profile_key), unicode(password), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='', + async_callbacks=('callback', 'errback')) + def asyncCreateProfile(self, profile, password='', callback=None, errback=None): + return self._callback("asyncCreateProfile", unicode(profile), unicode(password), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='s', out_signature='', + async_callbacks=('callback', 'errback')) + def asyncDeleteProfile(self, profile, callback=None, errback=None): + return self._callback("asyncDeleteProfile", unicode(profile), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sssis', out_signature='s', + async_callbacks=('callback', 'errback')) + def asyncGetParamA(self, name, category, attribute="value", security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("asyncGetParamA", unicode(name), unicode(category), unicode(attribute), security_limit, unicode(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sis', out_signature='a{ss}', + async_callbacks=('callback', 'errback')) + def asyncGetParamsValuesFromCategory(self, category, security_limit=-1, profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("asyncGetParamsValuesFromCategory", unicode(category), security_limit, unicode(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='', + async_callbacks=('callback', 'errback')) + def delContact(self, entity_jid, profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("delContact", unicode(entity_jid), unicode(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='(asa(sss)a{sa(a{ss}as)})', + async_callbacks=('callback', 'errback')) + def discoInfos(self, entity_jid, profile_key, callback=None, errback=None): + return self._callback("discoInfos", unicode(entity_jid), unicode(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='a(sss)', + async_callbacks=('callback', 'errback')) + def discoItems(self, entity_jid, profile_key, callback=None, errback=None): + return self._callback("discoItems", unicode(entity_jid), unicode(profile_key), callback=callback, errback=errback) + + @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._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._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=('callback', 'errback')) + def getContacts(self, profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("getContacts", unicode(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='as', + async_callbacks=None) + def getContactsFromGroup(self, group, profile_key="@DEFAULT@"): + return self._callback("getContactsFromGroup", unicode(group), unicode(profile_key)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='asass', out_signature='a{sa{ss}}', + async_callbacks=None) + def getEntitiesData(self, jids, keys, profile): + return self._callback("getEntitiesData", jids, keys, unicode(profile)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sass', out_signature='a{ss}', + async_callbacks=None) + def getEntityData(self, jid, keys, profile): + return self._callback("getEntityData", unicode(jid), keys, unicode(profile)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='s', out_signature='a{sa{ss}}', + async_callbacks=('callback', 'errback')) + def getFeatures(self, profile_key, callback=None, errback=None): + return self._callback("getFeatures", unicode(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='s', + async_callbacks=None) + def getMainResource(self, contact_jid, profile_key="@DEFAULT@"): + return self._callback("getMainResource", unicode(contact_jid), unicode(profile_key)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='s', + async_callbacks=None) + def getMenuHelp(self, menu_id, language): + return self._callback("getMenuHelp", unicode(menu_id), unicode(language)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='si', out_signature='a(ssasasa{ss})', + async_callbacks=None) + def getMenus(self, language, security_limit): + return self._callback("getMenus", unicode(language), security_limit) + + @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._callback("getParamA", unicode(name), unicode(category), unicode(attribute), unicode(profile_key)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='', out_signature='as', + async_callbacks=None) + def getParamsCategories(self, ): + return self._callback("getParamsCategories", ) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='iss', out_signature='s', + async_callbacks=('callback', 'errback')) + def getParamsUI(self, security_limit=-1, app='', profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("getParamsUI", security_limit, unicode(app), 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 getPresenceStatuses(self, profile_key="@DEFAULT@"): + return self._callback("getPresenceStatuses", 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._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._callback("getProfilesList", ) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='', out_signature='', + async_callbacks=('callback', 'errback')) + def getReady(self, callback=None, errback=None): + return self._callback("getReady", callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='', out_signature='s', + async_callbacks=None) + def getVersion(self, ): + 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._callback("getWaitingSub", unicode(profile_key)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ssiba{ss}s', out_signature='a(sdssa{ss}a{ss}sa{ss})', + async_callbacks=('callback', 'errback')) + def historyGet(self, from_jid, to_jid, limit, between=True, filters='', profile="@NONE@", callback=None, errback=None): + return self._callback("historyGet", unicode(from_jid), unicode(to_jid), limit, between, filters, unicode(profile), callback=callback, errback=errback) + + @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._callback("isConnected", unicode(profile_key)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sa{ss}s', out_signature='a{ss}', + async_callbacks=('callback', 'errback')) + def launchAction(self, callback_id, data, profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("launchAction", unicode(callback_id), data, unicode(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='s', out_signature='b', + async_callbacks=None) + def loadParamsTemplate(self, filename): + return self._callback("loadParamsTemplate", unicode(filename)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sa{ss}a{ss}sa{ss}s', out_signature='', + async_callbacks=('callback', 'errback')) + def messageSend(self, to_jid, message, subject={}, mess_type="auto", extra={}, profile_key="@NONE@", callback=None, errback=None): + return self._callback("messageSend", unicode(to_jid), message, subject, unicode(mess_type), extra, unicode(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sis', out_signature='', + async_callbacks=None) + def paramsRegisterApp(self, xml, security_limit=-1, app=''): + return self._callback("paramsRegisterApp", unicode(xml), security_limit, unicode(app)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='s', out_signature='b', + async_callbacks=None) + def profileIsSessionStarted(self, profile_key="@DEFAULT@"): + return self._callback("profileIsSessionStarted", unicode(profile_key)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='s', out_signature='', + async_callbacks=None) + def profileSetDefault(self, profile): + return self._callback("profileSetDefault", unicode(profile)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='b', + async_callbacks=('callback', 'errback')) + def profileStartSession(self, password='', profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("profileStartSession", unicode(password), unicode(profile_key), callback=callback, errback=errback) + + @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='a{sa{sa{ss}}}', + async_callbacks=None) + def progressGetAllMetadata(self, profile): + return self._callback("progressGetAllMetadata", unicode(profile)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='s', out_signature='b', + async_callbacks=None) + def saveParamsTemplate(self, filename): + return self._callback("saveParamsTemplate", unicode(filename)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='sssis', out_signature='', + async_callbacks=None) + def setParam(self, name, value, category, security_limit=-1, profile_key="@DEFAULT@"): + return self._callback("setParam", unicode(name), unicode(value), unicode(category), security_limit, unicode(profile_key)) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ssa{ss}s', out_signature='', + async_callbacks=None) + def setPresence(self, to_jid='', show='', statuses={}, profile_key="@DEFAULT@"): + return self._callback("setPresence", unicode(to_jid), unicode(show), 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._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=('callback', 'errback')) + def updateContact(self, entity_jid, name, groups, profile_key="@DEFAULT@", callback=None, errback=None): + return self._callback("updateContact", unicode(entity_jid), unicode(name), groups, unicode(profile_key), callback=callback, errback=errback) + + def __attributes(self, in_sign): + """Return arguments to user given a in_sign + @param in_sign: in_sign in the short form (using s,a,i,b etc) + @return: list of arguments that correspond to a in_sign (e.g.: "sss" return "arg1, arg2, arg3")""" + i = 0 + idx = 0 + attr = [] + while i < len(in_sign): + if in_sign[i] not in ['b', 'y', 'n', 'i', 'x', 'q', 'u', 't', 'd', 's', 'a']: + raise ParseError("Unmanaged attribute type [%c]" % in_sign[i]) + + attr.append("arg_%i" % idx) + idx += 1 + + if in_sign[i] == 'a': + i += 1 + if in_sign[i] != '{' and in_sign[i] != '(': # FIXME: must manage tuples out of arrays + i += 1 + continue # we have a simple type for the array + opening_car = in_sign[i] + assert(opening_car in ['{', '(']) + closing_car = '}' if opening_car == '{' else ')' + opening_count = 1 + while (True): # we have a dict or a list of tuples + i += 1 + if i >= len(in_sign): + raise ParseError("missing }") + if in_sign[i] == opening_car: + opening_count += 1 + if in_sign[i] == closing_car: + opening_count -= 1 + if opening_count == 0: + break + i += 1 + return attr + + def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False): + """Dynamically add a method to Dbus Bridge""" + inspect_args = inspect.getargspec(method) + + _arguments = inspect_args.args + _defaults = list(inspect_args.defaults or []) + + if inspect.ismethod(method): + #if we have a method, we don't want the first argument (usually 'self') + del(_arguments[0]) + + #first arguments are for the _callback method + arguments_callback = ', '.join([repr(name)] + ((_arguments + ['callback=callback', 'errback=errback']) if async else _arguments)) + + if async: + _arguments.extend(['callback', 'errback']) + _defaults.extend([None, None]) + + #now we create a second list with default values + for i in range(1, len(_defaults) + 1): + _arguments[-i] = "%s = %s" % (_arguments[-i], repr(_defaults[-i])) + + arguments_defaults = ', '.join(_arguments) + + code = compile('def %(name)s (self,%(arguments_defaults)s): return self._callback(%(arguments_callback)s)' % + {'name': name, 'arguments_defaults': arguments_defaults, 'arguments_callback': arguments_callback}, '', 'exec') + exec (code) # FIXME: to the same thing in a cleaner way, without compile/exec + method = locals()[name] + async_callbacks = ('callback', 'errback') if async else None + setattr(DbusObject, name, dbus.service.method( + const_INT_PREFIX + int_suffix, in_signature=in_sign, out_signature=out_sign, + async_callbacks=async_callbacks)(method)) + function = getattr(self, name) + func_table = self._dbus_class_table[self.__class__.__module__ + '.' + self.__class__.__name__][function._dbus_interface] + func_table[function.__name__] = function # Needed for introspection + + def addSignal(self, name, int_suffix, signature, doc={}): + """Dynamically add a signal to Dbus Bridge""" + attributes = ', '.join(self.__attributes(signature)) + #TODO: use doc parameter to name attributes + + #code = compile ('def '+name+' (self,'+attributes+'): log.debug ("'+name+' signal")', '','exec') #XXX: the log.debug is too annoying with xmllog + code = compile('def ' + name + ' (self,' + attributes + '): pass', '', 'exec') + exec (code) + signal = locals()[name] + setattr(DbusObject, name, dbus.service.signal( + const_INT_PREFIX + int_suffix, signature=signature)(signal)) + function = getattr(self, name) + func_table = self._dbus_class_table[self.__class__.__module__ + '.' + self.__class__.__name__][function._dbus_interface] + func_table[function.__name__] = function # Needed for introspection + + +class Bridge(object): + def __init__(self): + dbus.mainloop.glib.DBusGMainLoop(set_as_default=True) + log.info("Init DBus...") + try: + self.session_bus = dbus.SessionBus() + except dbus.DBusException as e: + if e._dbus_error_name == 'org.freedesktop.DBus.Error.NotSupported': + log.error(_(u"D-Bus is not launched, please see README to see instructions on how to launch it")) + raise BridgeInitError + self.dbus_name = dbus.service.BusName(const_INT_PREFIX, self.session_bus) + self.dbus_bridge = DbusObject(self.session_bus, const_OBJ_PATH) + + def actionNew(self, action_data, id, security_limit, profile): + self.dbus_bridge.actionNew(action_data, id, security_limit, profile) + + def connected(self, profile, jid_s): + self.dbus_bridge.connected(profile, jid_s) + + def contactDeleted(self, entity_jid, profile): + self.dbus_bridge.contactDeleted(entity_jid, profile) + + def disconnected(self, profile): + self.dbus_bridge.disconnected(profile) + + def entityDataUpdated(self, jid, name, value, profile): + self.dbus_bridge.entityDataUpdated(jid, name, value, profile) + + def messageNew(self, uid, timestamp, from_jid, to_jid, message, subject, mess_type, extra, profile): + self.dbus_bridge.messageNew(uid, timestamp, from_jid, to_jid, message, subject, mess_type, extra, profile) + + def newContact(self, contact_jid, attributes, groups, profile): + self.dbus_bridge.newContact(contact_jid, attributes, groups, profile) + + def paramUpdate(self, name, value, category, profile): + self.dbus_bridge.paramUpdate(name, value, category, profile) + + def presenceUpdate(self, entity_jid, show, priority, statuses, profile): + self.dbus_bridge.presenceUpdate(entity_jid, show, priority, statuses, profile) + + def progressError(self, id, error, profile): + self.dbus_bridge.progressError(id, error, profile) + + def progressFinished(self, id, metadata, profile): + self.dbus_bridge.progressFinished(id, metadata, profile) + + def progressStarted(self, id, metadata, profile): + self.dbus_bridge.progressStarted(id, metadata, profile) + + def subscribe(self, sub_type, entity_jid, profile): + self.dbus_bridge.subscribe(sub_type, entity_jid, profile) + + def register_method(self, name, callback): + log.debug("registering DBus bridge method [%s]" % name) + self.dbus_bridge.register_method(name, callback) + + def addMethod(self, name, int_suffix, in_sign, out_sign, method, async=False, doc={}): + """Dynamically add a method to Dbus Bridge""" + #FIXME: doc parameter is kept only temporary, the time to remove it from calls + log.debug("Adding method [%s] to DBus bridge" % name) + self.dbus_bridge.addMethod(name, int_suffix, in_sign, out_sign, method, async) + self.register_method(name, method) + + def addSignal(self, name, int_suffix, signature, doc={}): + self.dbus_bridge.addSignal(name, int_suffix, signature, doc) + setattr(Bridge, name, getattr(self.dbus_bridge, name)) \ No newline at end of file diff -r da4097de5a95 -r 4633cfcbcccb src/core/sat_main.py --- a/src/core/sat_main.py Sun Oct 02 22:44:33 2016 +0200 +++ b/src/core/sat_main.py Mon Oct 03 21:15:39 2016 +0200 @@ -25,7 +25,7 @@ from twisted.words.xish import domish from twisted.internet import reactor from wokkel.xmppim import RosterItem -from sat.bridge.DBus import DBusBridge +from sat.bridge.dbus_bridge import Bridge from sat.core import xmpp from sat.core import exceptions from sat.core.log import getLogger @@ -61,55 +61,55 @@ self.trigger = trigger.TriggerManager() # trigger are used to change SàT behaviour try: - self.bridge = DBusBridge() + self.bridge = Bridge() except exceptions.BridgeInitError: log.error(u"Bridge can't be initialised, can't start SàT core") sys.exit(1) - self.bridge.register("getReady", lambda: self.initialised) - self.bridge.register("getVersion", lambda: self.full_version) - self.bridge.register("getFeatures", self.getFeatures) - self.bridge.register("getProfileName", self.memory.getProfileName) - self.bridge.register("getProfilesList", self.memory.getProfilesList) - self.bridge.register("getEntityData", lambda jid_, keys, profile: self.memory.getEntityData(jid.JID(jid_), keys, profile)) - self.bridge.register("getEntitiesData", self.memory._getEntitiesData) - self.bridge.register("asyncCreateProfile", self.memory.asyncCreateProfile) - self.bridge.register("asyncDeleteProfile", self.memory.asyncDeleteProfile) - self.bridge.register("profileStartSession", self.memory.startSession) - self.bridge.register("profileIsSessionStarted", self.memory._isSessionStarted) - self.bridge.register("profileSetDefault", self.memory.profileSetDefault) - self.bridge.register("asyncConnect", self._asyncConnect) - self.bridge.register("disconnect", self.disconnect) - self.bridge.register("getContacts", self.getContacts) - self.bridge.register("getContactsFromGroup", self.getContactsFromGroup) - self.bridge.register("getMainResource", self.memory._getMainResource) - self.bridge.register("getPresenceStatuses", self.memory._getPresenceStatuses) - self.bridge.register("getWaitingSub", self.memory.getWaitingSub) - self.bridge.register("messageSend", self._messageSend) - self.bridge.register("getConfig", self._getConfig) - self.bridge.register("setParam", self.setParam) - self.bridge.register("getParamA", self.memory.getStringParamA) - self.bridge.register("asyncGetParamA", self.memory.asyncGetStringParamA) - self.bridge.register("asyncGetParamsValuesFromCategory", self.memory.asyncGetParamsValuesFromCategory) - self.bridge.register("getParamsUI", self.memory.getParamsUI) - self.bridge.register("getParamsCategories", self.memory.getParamsCategories) - self.bridge.register("paramsRegisterApp", self.memory.paramsRegisterApp) - self.bridge.register("historyGet", self.memory._historyGet) - self.bridge.register("setPresence", self._setPresence) - self.bridge.register("subscription", self.subscription) - self.bridge.register("addContact", self._addContact) - self.bridge.register("updateContact", self._updateContact) - 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("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) - self.bridge.register("discoItems", self.memory.disco._discoItems) - self.bridge.register("saveParamsTemplate", self.memory.save_xml) - self.bridge.register("loadParamsTemplate", self.memory.load_xml) + self.bridge.register_method("getReady", lambda: self.initialised) + self.bridge.register_method("getVersion", lambda: self.full_version) + self.bridge.register_method("getFeatures", self.getFeatures) + self.bridge.register_method("getProfileName", self.memory.getProfileName) + self.bridge.register_method("getProfilesList", self.memory.getProfilesList) + self.bridge.register_method("getEntityData", lambda jid_, keys, profile: self.memory.getEntityData(jid.JID(jid_), keys, profile)) + self.bridge.register_method("getEntitiesData", self.memory._getEntitiesData) + self.bridge.register_method("asyncCreateProfile", self.memory.asyncCreateProfile) + self.bridge.register_method("asyncDeleteProfile", self.memory.asyncDeleteProfile) + self.bridge.register_method("profileStartSession", self.memory.startSession) + self.bridge.register_method("profileIsSessionStarted", self.memory._isSessionStarted) + self.bridge.register_method("profileSetDefault", self.memory.profileSetDefault) + self.bridge.register_method("asyncConnect", self._asyncConnect) + self.bridge.register_method("disconnect", self.disconnect) + self.bridge.register_method("getContacts", self.getContacts) + self.bridge.register_method("getContactsFromGroup", self.getContactsFromGroup) + self.bridge.register_method("getMainResource", self.memory._getMainResource) + self.bridge.register_method("getPresenceStatuses", self.memory._getPresenceStatuses) + self.bridge.register_method("getWaitingSub", self.memory.getWaitingSub) + self.bridge.register_method("messageSend", self._messageSend) + self.bridge.register_method("getConfig", self._getConfig) + self.bridge.register_method("setParam", self.setParam) + self.bridge.register_method("getParamA", self.memory.getStringParamA) + self.bridge.register_method("asyncGetParamA", self.memory.asyncGetStringParamA) + self.bridge.register_method("asyncGetParamsValuesFromCategory", self.memory.asyncGetParamsValuesFromCategory) + self.bridge.register_method("getParamsUI", self.memory.getParamsUI) + self.bridge.register_method("getParamsCategories", self.memory.getParamsCategories) + self.bridge.register_method("paramsRegisterApp", self.memory.paramsRegisterApp) + self.bridge.register_method("historyGet", self.memory._historyGet) + self.bridge.register_method("setPresence", self._setPresence) + self.bridge.register_method("subscription", self.subscription) + self.bridge.register_method("addContact", self._addContact) + self.bridge.register_method("updateContact", self._updateContact) + self.bridge.register_method("delContact", self._delContact) + self.bridge.register_method("isConnected", self.isConnected) + self.bridge.register_method("launchAction", self.launchCallback) + self.bridge.register_method("actionsGet", self.actionsGet) + self.bridge.register_method("progressGet", self._progressGet) + self.bridge.register_method("progressGetAll", self._progressGetAll) + self.bridge.register_method("getMenus", self.getMenus) + self.bridge.register_method("getMenuHelp", self.getMenuHelp) + self.bridge.register_method("discoInfos", self.memory.disco._discoInfos) + self.bridge.register_method("discoItems", self.memory.disco._discoItems) + self.bridge.register_method("saveParamsTemplate", self.memory.save_xml) + self.bridge.register_method("loadParamsTemplate", self.memory.load_xml) self.memory.initialized.addCallback(self._postMemoryInit)