diff --git a/libervia/backend/bridge/bridge_constructor/base_constructor.py b/libervia/backend/bridge/bridge_constructor/base_constructor.py index 00cb535e..6d5ff925 100644 --- a/libervia/backend/bridge/bridge_constructor/base_constructor.py +++ b/libervia/backend/bridge/bridge_constructor/base_constructor.py @@ -306,8 +306,10 @@ class Constructor(object): extend_method(completion, function, default, arg_doc, async_) for part, fmt in FORMATS.items(): - if part.startswith(function["type"]) or part.startswith( - f"async_{function['type']}" + if ( + part.startswith(function["type"]) + or part.startswith(f"async_{function['type']}") + or part.startswith(f"twisted_{function['type']}") ): parts[part.upper()].append(fmt.format(**completion)) diff --git a/libervia/backend/bridge/bridge_constructor/constructors/dbus/constructor.py b/libervia/backend/bridge/bridge_constructor/constructors/dbus/constructor.py index 7c3014a9..4fc1d5c6 100644 --- a/libervia/backend/bridge/bridge_constructor/constructors/dbus/constructor.py +++ b/libervia/backend/bridge/bridge_constructor/constructors/dbus/constructor.py @@ -41,16 +41,14 @@ class DbusConstructor(base_constructor.Constructor): FRONTEND_DEST = CORE_DEST FRONTEND_FORMATS = { "methods": """\ - def {name}(self, {args}{async_comma}{async_args}): - {error_handler}{blocking_call}{debug}return {result}\n""", + def {name}(self, {args}): + {debug}return self.call("{name}", {args_result})\n""", "async_methods": """\ - def {name}(self{async_comma}{args}): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe(fut.set_exception, dbus_to_bridge_exception(err)) - self.db_{category}_iface.{name}({args_result}{async_comma}timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler) - {debug}return fut\n""", + async def {name}(self, {args}): + {debug}return await self.call("{name}", {args_result})\n""", + "twisted_methods": """\ + def {name}(self, {args}): + {debug}return self.call("{name}", {args_result})\n""", } def core_completion_signal(self, completion, function, default, arg_doc, async_): @@ -75,42 +73,11 @@ class DbusConstructor(base_constructor.Constructor): def frontend_completion_method(self, completion, function, default, arg_doc, async_): completion.update( { - # XXX: we can manage blocking call in the same way as async one: if callback is None the call will be blocking "debug": ( "" if not self.args.debug else 'log.debug ("%s")\n%s' % (completion["name"], 8 * " ") ), "args_result": self.get_arguments(function["sig_in"], name=arg_doc), - "async_args": "callback=None, errback=None", - "async_comma": ", " if function["sig_in"] else "", - "error_handler": """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)) - """, } ) - if async_: - completion["blocking_call"] = "" - completion["async_args_result"] = ( - "timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler" - ) - else: - # XXX: To have a blocking call, we must have not reply_handler, so we test if callback exists, and add reply_handler only in this case - completion["blocking_call"] = """kwargs={} - if callback is not None: - kwargs['timeout'] = const_TIMEOUT - kwargs['reply_handler'] = callback - kwargs['error_handler'] = error_handler - """ - completion["async_args_result"] = "**kwargs" - result = ( - "self.db_%(category)s_iface.%(name)s(%(args_result)s%(async_comma)s%(async_args_result)s)" - % completion - ) - completion["result"] = ( - "str(%s)" if self.args.unicode and function["sig_out"] == "s" else "%s" - ) % result diff --git a/libervia/backend/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py b/libervia/backend/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py index a19dca4f..4598bdd1 100644 --- a/libervia/backend/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py +++ b/libervia/backend/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -# SàT communication bridge -# Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) +# Libervia D-Bus communication bridge +# Copyright (C) 2009-2026 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 @@ -17,23 +17,17 @@ # along with this program. If not, see . import asyncio -import dbus -import ast -from libervia.backend.core.i18n import _ -from libervia.backend.tools import config -from libervia.backend.core.log import getLogger -from libervia.backend.core.exceptions import BridgeExceptionNoService, BridgeInitError -from dbus.mainloop.glib import DBusGMainLoop +from functools import partial + +from twisted.internet import reactor +from txdbus import client + from .bridge_frontend import BridgeException +from libervia.backend.core.exceptions import BridgeExceptionNoService, BridgeInitError +from libervia.backend.core.i18n import _ +from libervia.backend.core.log import getLogger +from libervia.backend.tools import config -# We check if GLib is actually available to avoid init error at a later stage. -try: - from gi.repository import GLib # type: ignore -except ImportError as e: - raise BridgeInitError(f"GLib is required for D-Bus bridge: {e}") - - -DBusGMainLoop(set_as_default=True) log = getLogger(__name__) @@ -48,207 +42,306 @@ const_PLUGIN_SUFFIX = ".plugin" const_TIMEOUT = 120 -def dbus_to_bridge_exception(dbus_e): - """Convert a DBusException to a BridgeException. +def dbus_to_bridge_exception(failure): + """Convert a txdbus Failure to a BridgeException. - @param dbus_e (DBusException) + @param failure (Failure or RemoteError) @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 :] + from twisted.python.failure import Failure + + if isinstance(failure, Failure): + err = failure.value + message = failure.getErrorMessage() + else: + err = failure + message = str(failure) + + full_name = getattr(err, "dbusErrorName", None) or getattr(err, "errName", None) + if full_name is None: + full_name = ".".join( + (const_ERROR_PREFIX, err.__class__.__module__, err.__class__.__name__) + ) + + if full_name and full_name.startswith(const_ERROR_PREFIX): + name = full_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) + + return BridgeException(name, message, "") + + +class SignalsHandler: + + def __init__(self, db_object, iface_name): + self.db_object = db_object + self._iface_names = { + "core": const_INT_PREFIX + const_CORE_SUFFIX, + "plugin": iface_name, + } + + def __getattr__(self, name): + if name.startswith("remote_"): + log.debug("calling an unregistered signal: {name}".format(name=name[7:])) + return lambda *args, **kwargs: None + else: + raise AttributeError(name) + + def register_signal(self, name, handler, iface="core"): + log.debug("registering signal {name}".format(name=name)) + method_name = "remote_" + name + try: + self.__getattribute__(method_name) + except AttributeError: + pass + else: + from libervia.backend.core import exceptions + + raise exceptions.InternalError( + "{name} signal handler has been registered twice".format(name=method_name) + ) + + def on_signal(*args): + handler(*args) + + d = self.db_object.notifyOnSignal( + name, on_signal, interface=self._iface_names[iface] + ) + d.addErrback( + lambda failure_: log.error( + f"Failed to register signal {name}: {failure_.getErrorMessage()}" + ) + ) + + setattr(self, method_name, on_signal) class bridge: - def bridge_connect(self, callback, errback): + def __init__(self): + self.conn = None + self.db_object = None + self.db_core_iface = None + self.db_plugin_iface = None + self.signals_handler = None + + def __getattr__(self, name): + return partial(self.call, name) + + @staticmethod + def _unwrap_txdbus_result(d, return_sig): + """Unwrap txdbus result.""" + # txdbus seems to wrongly wrap result in a list, this is a workaround. + # FIXME: check txdbus behaviour, and report upstream if it's confirmed to be a + # bug. + if return_sig and return_sig.startswith("("): + d.addCallback( + lambda result: ( + result[0] if isinstance(result, list) and len(result) == 1 else result + ) + ) + return d + + def call(self, name: str, *args, **kwargs): + """Call a remote method. + + @param name: name of the bridge method + @param args: method arguments + @param kwargs: keyword arguments (callback, errback, and methods arguments) + """ + # Determine which interface to use by checking where the method is defined + for iface in self.db_object.interfaces: + if name in iface.methods: + interface_name = iface.name + return_sig = iface.methods[name].sigOut + break + else: + # Default to core interface if method not found (will raise AttributeError) + interface_name = const_INT_PREFIX + const_CORE_SUFFIX + return_sig = None + + # Call the remote method + d = self.db_object.callRemote( + name, + *args, + interface=interface_name, + timeout=const_TIMEOUT, + ) + + self._unwrap_txdbus_result(d, return_sig) + + return d + + async def bridge_connect(self) -> None: + """Connect to the D-Bus bridge.""" try: - self.sessions_bus = dbus.SessionBus() - self.db_object = self.sessions_bus.get_object( + self.conn = await client.connect(reactor) + self.db_object = await self.conn.getRemoteObject( const_INT_PREFIX, const_OBJ_PATH ) - self.db_core_iface = dbus.Interface( - self.db_object, dbus_interface=const_INT_PREFIX + const_CORE_SUFFIX + # Find the core and plugin interfaces + for iface in self.db_object.interfaces: + if iface.name == const_INT_PREFIX + const_CORE_SUFFIX: + self.db_core_iface = iface + elif iface.name == const_INT_PREFIX + const_PLUGIN_SUFFIX: + self.db_plugin_iface = iface + + if self.db_core_iface is None: + raise BridgeInitError( + f"Core interface {const_INT_PREFIX + const_CORE_SUFFIX} not found" + ) + if self.db_plugin_iface is None: + raise BridgeInitError( + f"Plugin interface {const_INT_PREFIX + const_PLUGIN_SUFFIX} not found" + ) + + # Initialize signals handler + self.signals_handler = SignalsHandler( + self.db_object, const_INT_PREFIX + const_PLUGIN_SUFFIX ) - self.db_plugin_iface = dbus.Interface( - self.db_object, dbus_interface=const_INT_PREFIX + const_PLUGIN_SUFFIX - ) - except dbus.exceptions.DBusException as e: - if e._dbus_error_name in ( - "org.freedesktop.DBus.Error.ServiceUnknown", - "org.freedesktop.DBus.Error.Spawn.ExecFailed", + except BridgeInitError as e: + raise e + except Exception as e: + msg = str(e) + if ( + "org.freedesktop.DBus.Error.ServiceUnknown" in msg + or "org.freedesktop.DBus.Error.Spawn.ExecFailed" in msg ): - errback(BridgeExceptionNoService()) - elif e._dbus_error_name == "org.freedesktop.DBus.Error.NotSupported": + raise BridgeExceptionNoService from e + elif "org.freedesktop.DBus.Error.NotSupported" in msg: log.error( _( - "D-Bus is not launched, please see README to see instructions on how to launch it" + "D-Bus is not launched, please see README to see instructions on" + " how to launch it" ) ) - errback(BridgeInitError) - else: - errback(e) - else: - callback() - # props = self.db_core_iface.getProperties() + raise BridgeInitError from e 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 get_plugin_method(*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(str(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.warning( - "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) - ) - - try: - return method(*args, **kwargs) - except ValueError as e: - if e.args[0].startswith("Unable to guess signature"): - # XXX: if frontend is started too soon after backend, the - # inspection misses methods (notably plugin dynamically added - # methods). The following hack works around that by redoing the - # cache of introspected methods signatures. - log.debug("using hack to work around inspection issue") - proxy = self.db_plugin_iface.proxy_object - IN_PROGRESS = proxy.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS - proxy._introspect_state = IN_PROGRESS - proxy._Introspect() - return self.db_plugin_iface.get_dbus_method(name)(*args, **kwargs) - raise e - - return get_plugin_method + if self.signals_handler is None: + log.error("Bridge not initialized") + return + self.signals_handler.register_signal(functionName, handler, iface) ##METHODS_PART## -class AIOBridge(bridge): +class AIOSignalsHandler(SignalsHandler): - async def post_init(self) -> None: - pass - - def register_signal(self, functionName, handler, iface="core"): - loop = asyncio.get_running_loop() - async_handler = lambda *args: asyncio.run_coroutine_threadsafe( - handler(*args), loop - ) - return super().register_signal(functionName, async_handler, iface) - - 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 get_plugin_method(*args, **kwargs): - loop = asyncio.get_running_loop() - fut = loop.create_future() - method = getattr(self.db_plugin_iface, name) - reply_handler = lambda ret=None: loop.call_soon_threadsafe( - fut.set_result, ret - ) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - try: - method( - *args, - **kwargs, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - except ValueError as e: - if e.args[0].startswith("Unable to guess signature"): - # same hack as for bridge.__getattribute__ - log.warning("using hack to work around inspection issue") - proxy = self.db_plugin_iface.proxy_object - IN_PROGRESS = proxy.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS - proxy._introspect_state = IN_PROGRESS - proxy._Introspect() - self.db_plugin_iface.get_dbus_method(name)( - *args, - **kwargs, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - - else: - raise e - return fut - - return get_plugin_method - - def bridge_connect(self): - loop = asyncio.get_running_loop() - fut = loop.create_future() - super().bridge_connect( - callback=lambda: loop.call_soon_threadsafe(fut.set_result, None), - errback=lambda e: loop.call_soon_threadsafe(fut.set_exception, e), - ) - return fut + def register_signal(self, name, handler, iface="core"): + """Register an async signal handler.""" + async_handler = lambda *args: asyncio.ensure_future(handler(*args)) + return super().register_signal(name, async_handler, iface) ##ASYNC_METHODS_PART## + + +class AIOBridge(bridge): + + def __init__(self): + super().__init__() + self.signals_handler = None + + async def post_init(self): + """Post-initialization hook. + + Actually no post init is needed, but the "__getattr__" return "partial" for + unknown methods, and this causes "dynamic_import.load_and_init_bridge" to fail. + """ + pass + + def call(self, name: str, *args, **kwargs): + """Call a remote method and return an awaitable. + + @param name: name of the bridge method + """ + d = super().call(name, *args, **kwargs) + return d.asFuture(asyncio.get_event_loop()) + + async def bridge_connect(self): + """Connect to the D-Bus bridge (async version).""" + try: + self.conn = await client.connect(reactor).asFuture(asyncio.get_event_loop()) + self.db_object = await self.conn.getRemoteObject( + const_INT_PREFIX, const_OBJ_PATH + ).asFuture(asyncio.get_event_loop()) + + # Find the core and plugin interfaces + for iface in self.db_object.interfaces: + if iface.name == const_INT_PREFIX + const_CORE_SUFFIX: + self.db_core_iface = iface + elif iface.name == const_INT_PREFIX + const_PLUGIN_SUFFIX: + self.db_plugin_iface = iface + + if self.db_core_iface is None: + raise BridgeInitError( + f"Core interface {const_INT_PREFIX + const_CORE_SUFFIX} not found" + ) + if self.db_plugin_iface is None: + raise BridgeInitError( + f"Plugin interface {const_INT_PREFIX + const_PLUGIN_SUFFIX} not found" + ) + + # Initialize signals handler + self.signals_handler = AIOSignalsHandler( + self.db_object, const_INT_PREFIX + const_PLUGIN_SUFFIX + ) + except BridgeInitError as e: + raise e + except Exception as e: + msg = str(e) + if ( + "org.freedesktop.DBus.Error.ServiceUnknown" in msg + or "org.freedesktop.DBus.Error.Spawn.ExecFailed" in msg + ): + raise BridgeExceptionNoService from e + elif "org.freedesktop.DBus.Error.NotSupported" in msg: + log.error( + _( + "D-Bus is not launched, please see README to see instructions on" + " how to launch it" + ) + ) + raise BridgeInitError from e + + def register_signal(self, functionName, handler, iface="core"): + if self.signals_handler is None: + log.error("Bridge not initialized") + return + self.signals_handler.register_signal(functionName, handler, iface) + + +class TwistedBridge(bridge): + + async def post_init(self): + """Post-initialization hook. + + Actually no post init is needed, but the "__getattr__" return "partial" for + unknown methods, and this causes "dynamic_import.load_and_init_bridge" to fail. + """ + pass + + def _errback(self, failure_): + """Convert Failure to BridgeException""" + raise dbus_to_bridge_exception(failure_) + + def call(self, name, *args, **kwargs): + """Call a remote method and return a Deferred. + + @param name(str): name of the bridge method + @param args(list): arguments + @param kwargs(dict): keyword arguments (profile, etc.) + """ + return super().call(name, *args, **kwargs) + + async def bridge_connect(self) -> None: + """Connect to the D-Bus bridge.""" + return await super().bridge_connect() + + def register_signal(self, functionName, handler, iface="core"): + super().register_signal(functionName, handler, iface) + + +##TWISTED_METHODS_PART## diff --git a/libervia/frontends/bridge/dbus_bridge.py b/libervia/frontends/bridge/dbus_bridge.py index 849bcca4..83637af2 100644 --- a/libervia/frontends/bridge/dbus_bridge.py +++ b/libervia/frontends/bridge/dbus_bridge.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -# SàT communication bridge -# Copyright (C) 2009-2021 Jérôme Poisson (goffi@goffi.org) +# Libervia D-Bus communication bridge +# Copyright (C) 2009-2026 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 @@ -17,23 +17,17 @@ # along with this program. If not, see . import asyncio -import dbus -import ast -from libervia.backend.core.i18n import _ -from libervia.backend.tools import config -from libervia.backend.core.log import getLogger -from libervia.backend.core.exceptions import BridgeExceptionNoService, BridgeInitError -from dbus.mainloop.glib import DBusGMainLoop +from functools import partial + +from twisted.internet import reactor +from txdbus import client + from .bridge_frontend import BridgeException +from libervia.backend.core.exceptions import BridgeExceptionNoService, BridgeInitError +from libervia.backend.core.i18n import _ +from libervia.backend.core.log import getLogger +from libervia.backend.tools import config -# We check if GLib is actually available to avoid init error at a later stage. -try: - from gi.repository import GLib # type: ignore -except ImportError as e: - raise BridgeInitError(f"GLib is required for D-Bus bridge: {e}") - - -DBusGMainLoop(set_as_default=True) log = getLogger(__name__) @@ -48,1695 +42,219 @@ const_PLUGIN_SUFFIX = ".plugin" const_TIMEOUT = 120 -def dbus_to_bridge_exception(dbus_e): - """Convert a DBusException to a BridgeException. +def dbus_to_bridge_exception(failure): + """Convert a txdbus Failure to a BridgeException. - @param dbus_e (DBusException) + @param failure (Failure or RemoteError) @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 :] + from twisted.python.failure import Failure + + if isinstance(failure, Failure): + err = failure.value + message = failure.getErrorMessage() + else: + err = failure + message = str(failure) + + full_name = getattr(err, "dbusErrorName", None) or getattr(err, "errName", None) + if full_name is None: + full_name = ".".join( + (const_ERROR_PREFIX, err.__class__.__module__, err.__class__.__name__) + ) + + if full_name and full_name.startswith(const_ERROR_PREFIX): + name = full_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) + + return BridgeException(name, message, "") + + +class SignalsHandler: + + def __init__(self, db_object, iface_name): + self.db_object = db_object + self._iface_names = { + "core": const_INT_PREFIX + const_CORE_SUFFIX, + "plugin": iface_name, + } + + def __getattr__(self, name): + if name.startswith("remote_"): + log.debug("calling an unregistered signal: {name}".format(name=name[7:])) + return lambda *args, **kwargs: None + else: + raise AttributeError(name) + + def register_signal(self, name, handler, iface="core"): + log.debug("registering signal {name}".format(name=name)) + method_name = "remote_" + name + try: + self.__getattribute__(method_name) + except AttributeError: + pass + else: + from libervia.backend.core import exceptions + + raise exceptions.InternalError( + "{name} signal handler has been registered twice".format(name=method_name) + ) + + def on_signal(*args): + handler(*args) + + d = self.db_object.notifyOnSignal( + name, on_signal, interface=self._iface_names[iface] + ) + d.addErrback( + lambda failure_: log.error( + f"Failed to register signal {name}: {failure_.getErrorMessage()}" + ) + ) + + setattr(self, method_name, on_signal) class bridge: - def bridge_connect(self, callback, errback): + def __init__(self): + self.conn = None + self.db_object = None + self.db_core_iface = None + self.db_plugin_iface = None + self.signals_handler = None + + def __getattr__(self, name): + return partial(self.call, name) + + @staticmethod + def _unwrap_txdbus_result(d, return_sig): + """Unwrap txdbus result.""" + # txdbus seems to wrongly wrap result in a list, this is a workaround. + # FIXME: check txdbus behaviour, and report upstream if it's confirmed to be a + # bug. + if return_sig and return_sig.startswith("("): + d.addCallback( + lambda result: ( + result[0] if isinstance(result, list) and len(result) == 1 else result + ) + ) + return d + + def call(self, name: str, *args, **kwargs): + """Call a remote method. + + @param name: name of the bridge method + @param args: method arguments + @param kwargs: keyword arguments (callback, errback, and methods arguments) + """ + # Determine which interface to use by checking where the method is defined + for iface in self.db_object.interfaces: + if name in iface.methods: + interface_name = iface.name + return_sig = iface.methods[name].sigOut + break + else: + # Default to core interface if method not found (will raise AttributeError) + interface_name = const_INT_PREFIX + const_CORE_SUFFIX + return_sig = None + + # Call the remote method + d = self.db_object.callRemote( + name, + *args, + interface=interface_name, + timeout=const_TIMEOUT, + ) + + self._unwrap_txdbus_result(d, return_sig) + + return d + + async def bridge_connect(self) -> None: + """Connect to the D-Bus bridge.""" try: - self.sessions_bus = dbus.SessionBus() - self.db_object = self.sessions_bus.get_object( + self.conn = await client.connect(reactor) + self.db_object = await self.conn.getRemoteObject( const_INT_PREFIX, const_OBJ_PATH ) - self.db_core_iface = dbus.Interface( - self.db_object, dbus_interface=const_INT_PREFIX + const_CORE_SUFFIX + # Find the core and plugin interfaces + for iface in self.db_object.interfaces: + if iface.name == const_INT_PREFIX + const_CORE_SUFFIX: + self.db_core_iface = iface + elif iface.name == const_INT_PREFIX + const_PLUGIN_SUFFIX: + self.db_plugin_iface = iface + + if self.db_core_iface is None: + raise BridgeInitError( + f"Core interface {const_INT_PREFIX + const_CORE_SUFFIX} not found" + ) + if self.db_plugin_iface is None: + raise BridgeInitError( + f"Plugin interface {const_INT_PREFIX + const_PLUGIN_SUFFIX} not found" + ) + + # Initialize signals handler + self.signals_handler = SignalsHandler( + self.db_object, const_INT_PREFIX + const_PLUGIN_SUFFIX ) - self.db_plugin_iface = dbus.Interface( - self.db_object, dbus_interface=const_INT_PREFIX + const_PLUGIN_SUFFIX - ) - except dbus.exceptions.DBusException as e: - if e._dbus_error_name in ( - "org.freedesktop.DBus.Error.ServiceUnknown", - "org.freedesktop.DBus.Error.Spawn.ExecFailed", + except BridgeInitError as e: + raise e + except Exception as e: + msg = str(e) + if ( + "org.freedesktop.DBus.Error.ServiceUnknown" in msg + or "org.freedesktop.DBus.Error.Spawn.ExecFailed" in msg ): - errback(BridgeExceptionNoService()) - elif e._dbus_error_name == "org.freedesktop.DBus.Error.NotSupported": + raise BridgeExceptionNoService from e + elif "org.freedesktop.DBus.Error.NotSupported" in msg: log.error( _( - "D-Bus is not launched, please see README to see instructions on how to launch it" + "D-Bus is not launched, please see README to see instructions on" + " how to launch it" ) ) - errback(BridgeInitError) - else: - errback(e) - else: - callback() - # props = self.db_core_iface.getProperties() + raise BridgeInitError from e 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 get_plugin_method(*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(str(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.warning( - "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) - ) - - try: - return method(*args, **kwargs) - except ValueError as e: - if e.args[0].startswith("Unable to guess signature"): - # XXX: if frontend is started too soon after backend, the - # inspection misses methods (notably plugin dynamically added - # methods). The following hack works around that by redoing the - # cache of introspected methods signatures. - log.debug("using hack to work around inspection issue") - proxy = self.db_plugin_iface.proxy_object - IN_PROGRESS = proxy.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS - proxy._introspect_state = IN_PROGRESS - proxy._Introspect() - return self.db_plugin_iface.get_dbus_method(name)(*args, **kwargs) - raise e - - return get_plugin_method - - def action_launch( - 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 str( - self.db_core_iface.action_launch( - callback_id, - data, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def actions_get(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.actions_get(profile_key, **kwargs) - - def config_get(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 str(self.db_core_iface.config_get(section, name, **kwargs)) - - def connect( - self, - profile_key="@DEFAULT@", - password="", - options={}, - 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.connect( - profile_key, - password, - options, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def contact_add( - 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.contact_add(entity_jid, profile_key, **kwargs) - - def contact_del( - 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.contact_del( - entity_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def contact_get(self, arg_0, 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.contact_get( - arg_0, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def contact_update( - 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)) - kwargs = {} - if callback is not None: - kwargs["timeout"] = const_TIMEOUT - kwargs["reply_handler"] = callback - kwargs["error_handler"] = error_handler - return self.db_core_iface.contact_update( - entity_jid, name, groups, profile_key, **kwargs - ) - - def contacts_get(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.contacts_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def contacts_get_from_group( - 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.contacts_get_from_group(group, profile_key, **kwargs) - - def devices_infos_get(self, bare_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 str( - self.db_core_iface.devices_infos_get( - bare_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def disco_find_by_features( - self, - namespaces, - identities, - bare_jid=False, - service=True, - roster=True, - own_jid=True, - local_device=False, - 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.disco_find_by_features( - namespaces, - identities, - bare_jid, - service, - roster, - own_jid, - local_device, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def disco_infos( - self, - entity_jid, - node="", - use_cache=True, - 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.disco_infos( - entity_jid, - node, - use_cache, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def disco_items( - self, - entity_jid, - node="", - use_cache=True, - 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.disco_items( - entity_jid, - node, - use_cache, - 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)) - return self.db_core_iface.disconnect( - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def encryption_namespace_get(self, arg_0, 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 str(self.db_core_iface.encryption_namespace_get(arg_0, **kwargs)) - - def encryption_plugins_get(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 str(self.db_core_iface.encryption_plugins_get(**kwargs)) - - def encryption_trust_ui_get( - self, to_jid, namespace, 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 str( - self.db_core_iface.encryption_trust_ui_get( - to_jid, - namespace, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def entities_data_get(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.entities_data_get(jids, keys, profile, **kwargs) - - def entity_data_get(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.entity_data_get(jid, keys, profile, **kwargs) - - def features_get(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.features_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def history_get( - 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.history_get( - from_jid, - to_jid, - limit, - between, - filters, - profile, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def image_check(self, arg_0, 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 str(self.db_core_iface.image_check(arg_0, **kwargs)) - - def image_convert(self, source, dest, arg_2, extra, 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 str( - self.db_core_iface.image_convert( - source, - dest, - arg_2, - extra, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def image_generate_preview( - self, image_path, 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 str( - self.db_core_iface.image_generate_preview( - image_path, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def image_resize(self, image_path, width, height, 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 str( - self.db_core_iface.image_resize( - image_path, - width, - height, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def init_pre_script(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.init_pre_script( - timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler - ) - - def is_connected(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.is_connected(profile_key, **kwargs) - - def main_resource_get( - 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 str( - self.db_core_iface.main_resource_get(contact_jid, profile_key, **kwargs) - ) - - def menu_help_get(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 str(self.db_core_iface.menu_help_get(menu_id, language, **kwargs)) - - def menu_launch( - self, - menu_type, - path, - data, - security_limit, - 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.menu_launch( - menu_type, - path, - data, - security_limit, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def menus_get(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.menus_get(language, security_limit, **kwargs) - - def message_encryption_get(self, to_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)) - kwargs = {} - if callback is not None: - kwargs["timeout"] = const_TIMEOUT - kwargs["reply_handler"] = callback - kwargs["error_handler"] = error_handler - return str( - self.db_core_iface.message_encryption_get(to_jid, profile_key, **kwargs) - ) - - def message_encryption_start( - self, - to_jid, - namespace="", - replace=False, - 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.message_encryption_start( - to_jid, - namespace, - replace, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def message_encryption_stop(self, to_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.message_encryption_stop( - to_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def message_send( - 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.message_send( - to_jid, - message, - subject, - mess_type, - extra, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def namespaces_get(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.namespaces_get(**kwargs) - - def notification_add( - self, - type_, - body_plain, - body_rich, - title, - is_global, - requires_action, - arg_6, - priority, - expire_at, - extra, - 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.notification_add( - type_, - body_plain, - body_rich, - title, - is_global, - requires_action, - arg_6, - priority, - expire_at, - extra, - **kwargs, - ) - - def notification_delete( - self, id_, is_global, 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)) - kwargs = {} - if callback is not None: - kwargs["timeout"] = const_TIMEOUT - kwargs["reply_handler"] = callback - kwargs["error_handler"] = error_handler - return self.db_core_iface.notification_delete( - id_, is_global, profile_key, **kwargs - ) - - def notifications_expired_clean( - self, limit_timestamp, 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)) - kwargs = {} - if callback is not None: - kwargs["timeout"] = const_TIMEOUT - kwargs["reply_handler"] = callback - kwargs["error_handler"] = error_handler - return self.db_core_iface.notifications_expired_clean( - limit_timestamp, profile_key, **kwargs - ) - - def notifications_get(self, filters, 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)) - kwargs = {} - if callback is not None: - kwargs["timeout"] = const_TIMEOUT - kwargs["reply_handler"] = callback - kwargs["error_handler"] = error_handler - return str(self.db_core_iface.notifications_get(filters, profile_key, **kwargs)) - - def param_get_a( - 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 str( - self.db_core_iface.param_get_a( - name, category, attribute, profile_key, **kwargs - ) - ) - - def param_get_a_async( - 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 str( - self.db_core_iface.param_get_a_async( - name, - category, - attribute, - security_limit, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def param_set( - 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.param_set( - name, value, category, security_limit, profile_key, **kwargs - ) - - def param_ui_get( - self, - security_limit=-1, - app="", - extra="", - 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 str( - self.db_core_iface.param_ui_get( - security_limit, - app, - extra, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def params_categories_get(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.params_categories_get(**kwargs) - - def params_register_app( - 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.params_register_app(xml, security_limit, app, **kwargs) - - def params_template_load(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.params_template_load(filename, **kwargs) - - def params_template_save(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.params_template_save(filename, **kwargs) - - def params_values_from_category_get_async( - self, - category, - security_limit=-1, - app="", - extra="", - 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.params_values_from_category_get_async( - category, - security_limit, - app, - extra, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def presence_set( - 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.presence_set( - to_jid, show, statuses, profile_key, **kwargs - ) - - def presence_statuses_get(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.presence_statuses_get(profile_key, **kwargs) - - def private_data_delete(self, namespace, key, arg_2, 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.private_data_delete( - namespace, - key, - arg_2, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def private_data_get(self, namespace, key, 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 str( - self.db_core_iface.private_data_get( - namespace, - key, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def private_data_set( - self, namespace, key, data, 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.private_data_set( - namespace, - key, - data, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def profile_create( - self, profile, password="", component="", 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.profile_create( - profile, - password, - component, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def profile_delete_async(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.profile_delete_async( - profile, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def profile_is_session_started( - 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.profile_is_session_started(profile_key, **kwargs) - - def profile_name_get(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 str(self.db_core_iface.profile_name_get(profile_key, **kwargs)) - - def profile_set_default(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.profile_set_default(profile, **kwargs) - - def profile_start_session( - 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.profile_start_session( - password, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def profiles_list_get( - self, clients=True, components=False, 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.profiles_list_get(clients, components, **kwargs) - - def progress_get(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.progress_get(id, profile, **kwargs) - - def progress_get_all(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.progress_get_all(profile, **kwargs) - - def progress_get_all_metadata(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.progress_get_all_metadata(profile, **kwargs) - - def ready_get(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.ready_get( - timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler - ) - - def roster_resync(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.roster_resync( - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def session_infos_get(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.session_infos_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - - def sub_waiting_get(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.sub_waiting_get(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 tor_infos_get(self, extra, 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 str( - self.db_core_iface.tor_infos_get( - extra, - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def tor_mode_get(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 str( - self.db_core_iface.tor_mode_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=callback, - error_handler=error_handler, - ) - ) - - def version_get(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 str(self.db_core_iface.version_get(**kwargs)) - - -class AIOBridge(bridge): - - async def post_init(self) -> None: - pass - - def register_signal(self, functionName, handler, iface="core"): - loop = asyncio.get_running_loop() - async_handler = lambda *args: asyncio.run_coroutine_threadsafe( - handler(*args), loop - ) - return super().register_signal(functionName, async_handler, iface) - - 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 get_plugin_method(*args, **kwargs): - loop = asyncio.get_running_loop() - fut = loop.create_future() - method = getattr(self.db_plugin_iface, name) - reply_handler = lambda ret=None: loop.call_soon_threadsafe( - fut.set_result, ret - ) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - try: - method( - *args, - **kwargs, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - except ValueError as e: - if e.args[0].startswith("Unable to guess signature"): - # same hack as for bridge.__getattribute__ - log.warning("using hack to work around inspection issue") - proxy = self.db_plugin_iface.proxy_object - IN_PROGRESS = proxy.INTROSPECT_STATE_INTROSPECT_IN_PROGRESS - proxy._introspect_state = IN_PROGRESS - proxy._Introspect() - self.db_plugin_iface.get_dbus_method(name)( - *args, - **kwargs, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - - else: - raise e - return fut - - return get_plugin_method - - def bridge_connect(self): - loop = asyncio.get_running_loop() - fut = loop.create_future() - super().bridge_connect( - callback=lambda: loop.call_soon_threadsafe(fut.set_result, None), - errback=lambda e: loop.call_soon_threadsafe(fut.set_exception, e), - ) - return fut + if self.signals_handler is None: + log.error("Bridge not initialized") + return + self.signals_handler.register_signal(functionName, handler, iface) def action_launch(self, callback_id, data, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.action_launch( - callback_id, - data, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("action_launch", callback_id, data, profile_key) def actions_get(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.actions_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("actions_get", profile_key) def config_get(self, section, name): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.config_get( - section, - name, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("config_get", section, name) def connect(self, profile_key="@DEFAULT@", password="", options={}): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.connect( - profile_key, - password, - options, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("connect", profile_key, password, options) def contact_add(self, entity_jid, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.contact_add( - entity_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("contact_add", entity_jid, profile_key) def contact_del(self, entity_jid, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.contact_del( - entity_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("contact_del", entity_jid, profile_key) def contact_get(self, arg_0, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.contact_get( - arg_0, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("contact_get", arg_0, profile_key) def contact_update(self, entity_jid, name, groups, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.contact_update( - entity_jid, - name, - groups, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("contact_update", entity_jid, name, groups, profile_key) def contacts_get(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.contacts_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("contacts_get", profile_key) def contacts_get_from_group(self, group, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.contacts_get_from_group( - group, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("contacts_get_from_group", group, profile_key) def devices_infos_get(self, bare_jid, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.devices_infos_get( - bare_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("devices_infos_get", bare_jid, profile_key) def disco_find_by_features( self, @@ -1749,13 +267,8 @@ class AIOBridge(bridge): local_device=False, profile_key="@DEFAULT@", ): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.disco_find_by_features( + return self.call( + "disco_find_by_features", namespaces, identities, bare_jid, @@ -1764,393 +277,94 @@ class AIOBridge(bridge): own_jid, local_device, profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, ) - return fut def disco_infos(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.disco_infos( - entity_jid, - node, - use_cache, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("disco_infos", entity_jid, node, use_cache, profile_key) def disco_items(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.disco_items( - entity_jid, - node, - use_cache, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("disco_items", entity_jid, node, use_cache, profile_key) def disconnect(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.disconnect( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("disconnect", profile_key) def encryption_namespace_get(self, arg_0): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.encryption_namespace_get( - arg_0, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("encryption_namespace_get", arg_0) - def encryption_plugins_get(self): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + def encryption_plugins_get( + self, + ): + return self.call( + "encryption_plugins_get", ) - self.db_core_iface.encryption_plugins_get( - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def encryption_trust_ui_get(self, to_jid, namespace, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.encryption_trust_ui_get( - to_jid, - namespace, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("encryption_trust_ui_get", to_jid, namespace, profile_key) def entities_data_get(self, jids, keys, profile): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.entities_data_get( - jids, - keys, - profile, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("entities_data_get", jids, keys, profile) def entity_data_get(self, jid, keys, profile): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.entity_data_get( - jid, - keys, - profile, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("entity_data_get", jid, keys, profile) def features_get(self, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.features_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("features_get", profile_key) def history_get( self, from_jid, to_jid, limit, between=True, filters="", profile="@NONE@" ): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + return self.call( + "history_get", from_jid, to_jid, limit, between, filters, profile ) - self.db_core_iface.history_get( - from_jid, - to_jid, - limit, - between, - filters, - profile, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def image_check(self, arg_0): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.image_check( - arg_0, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("image_check", arg_0) def image_convert(self, source, dest, arg_2, extra): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.image_convert( - source, - dest, - arg_2, - extra, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("image_convert", source, dest, arg_2, extra) def image_generate_preview(self, image_path, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.image_generate_preview( - image_path, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("image_generate_preview", image_path, profile_key) def image_resize(self, image_path, width, height): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.image_resize( - image_path, - width, - height, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("image_resize", image_path, width, height) - def init_pre_script(self): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + def init_pre_script( + self, + ): + return self.call( + "init_pre_script", ) - self.db_core_iface.init_pre_script( - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def is_connected(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.is_connected( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("is_connected", profile_key) def main_resource_get(self, contact_jid, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.main_resource_get( - contact_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("main_resource_get", contact_jid, profile_key) def menu_help_get(self, menu_id, language): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.menu_help_get( - menu_id, - language, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("menu_help_get", menu_id, language) def menu_launch(self, menu_type, path, data, security_limit, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + return self.call( + "menu_launch", menu_type, path, data, security_limit, profile_key ) - self.db_core_iface.menu_launch( - menu_type, - path, - data, - security_limit, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def menus_get(self, language, security_limit): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.menus_get( - language, - security_limit, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("menus_get", language, security_limit) def message_encryption_get(self, to_jid, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.message_encryption_get( - to_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("message_encryption_get", to_jid, profile_key) def message_encryption_start( self, to_jid, namespace="", replace=False, profile_key="@NONE@" ): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + return self.call( + "message_encryption_start", to_jid, namespace, replace, profile_key ) - self.db_core_iface.message_encryption_start( - to_jid, - namespace, - replace, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def message_encryption_stop(self, to_jid, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.message_encryption_stop( - to_jid, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("message_encryption_stop", to_jid, profile_key) def message_send( self, @@ -2161,38 +375,16 @@ class AIOBridge(bridge): extra={}, profile_key="@NONE@", ): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + return self.call( + "message_send", to_jid, message, subject, mess_type, extra, profile_key ) - self.db_core_iface.message_send( - to_jid, - message, - subject, - mess_type, - extra, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut - def namespaces_get(self): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + def namespaces_get( + self, + ): + return self.call( + "namespaces_get", ) - self.db_core_iface.namespaces_get( - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def notification_add( self, @@ -2207,13 +399,8 @@ class AIOBridge(bridge): expire_at, extra, ): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.notification_add( + return self.call( + "notification_add", type_, body_plain, body_rich, @@ -2224,78 +411,19 @@ class AIOBridge(bridge): priority, expire_at, extra, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, ) - return fut def notification_delete(self, id_, is_global, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.notification_delete( - id_, - is_global, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("notification_delete", id_, is_global, profile_key) def notifications_expired_clean(self, limit_timestamp, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.notifications_expired_clean( - limit_timestamp, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("notifications_expired_clean", limit_timestamp, profile_key) def notifications_get(self, filters, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.notifications_get( - filters, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("notifications_get", filters, profile_key) def param_get_a(self, name, category, attribute="value", profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.param_get_a( - name, - category, - attribute, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("param_get_a", name, category, attribute, profile_key) def param_get_a_async( self, @@ -2305,502 +433,901 @@ class AIOBridge(bridge): security_limit=-1, profile_key="@DEFAULT@", ): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + return self.call( + "param_get_a_async", name, category, attribute, security_limit, profile_key ) - self.db_core_iface.param_get_a_async( - name, - category, - attribute, - security_limit, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def param_set( self, name, value, category, security_limit=-1, profile_key="@DEFAULT@" ): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.param_set( - name, - value, - category, - security_limit, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("param_set", name, value, category, security_limit, profile_key) def param_ui_get(self, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.param_ui_get( - security_limit, - app, - extra, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("param_ui_get", security_limit, app, extra, profile_key) - def params_categories_get(self): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + def params_categories_get( + self, + ): + return self.call( + "params_categories_get", ) - self.db_core_iface.params_categories_get( - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def params_register_app(self, xml, security_limit=-1, app=""): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.params_register_app( - xml, - security_limit, - app, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("params_register_app", xml, security_limit, app) def params_template_load(self, filename): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.params_template_load( - filename, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("params_template_load", filename) def params_template_save(self, filename): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.params_template_save( - filename, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("params_template_save", filename) def params_values_from_category_get_async( self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@" ): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.params_values_from_category_get_async( + return self.call( + "params_values_from_category_get_async", category, security_limit, app, extra, profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, ) - return fut def presence_set(self, to_jid="", show="", statuses={}, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.presence_set( - to_jid, - show, - statuses, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("presence_set", to_jid, show, statuses, profile_key) def presence_statuses_get(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.presence_statuses_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("presence_statuses_get", profile_key) def private_data_delete(self, namespace, key, arg_2): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.private_data_delete( - namespace, - key, - arg_2, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("private_data_delete", namespace, key, arg_2) def private_data_get(self, namespace, key, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.private_data_get( - namespace, - key, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("private_data_get", namespace, key, profile_key) def private_data_set(self, namespace, key, data, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.private_data_set( - namespace, - key, - data, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("private_data_set", namespace, key, data, profile_key) def profile_create(self, profile, password="", component=""): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.profile_create( - profile, - password, - component, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("profile_create", profile, password, component) def profile_delete_async(self, profile): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.profile_delete_async( - profile, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("profile_delete_async", profile) def profile_is_session_started(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.profile_is_session_started( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("profile_is_session_started", profile_key) def profile_name_get(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.profile_name_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("profile_name_get", profile_key) def profile_set_default(self, profile): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.profile_set_default( - profile, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("profile_set_default", profile) def profile_start_session(self, password="", profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.profile_start_session( - password, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("profile_start_session", password, profile_key) def profiles_list_get(self, clients=True, components=False): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.profiles_list_get( - clients, - components, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("profiles_list_get", clients, components) def progress_get(self, id, profile): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.progress_get( - id, - profile, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("progress_get", id, profile) def progress_get_all(self, profile): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.progress_get_all( - profile, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("progress_get_all", profile) def progress_get_all_metadata(self, profile): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.progress_get_all_metadata( - profile, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("progress_get_all_metadata", profile) - def ready_get(self): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + def ready_get( + self, + ): + return self.call( + "ready_get", ) - self.db_core_iface.ready_get( - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut def roster_resync(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.roster_resync( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("roster_resync", profile_key) def session_infos_get(self, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.session_infos_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("session_infos_get", profile_key) def sub_waiting_get(self, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.sub_waiting_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("sub_waiting_get", profile_key) def subscription(self, sub_type, entity, profile_key="@DEFAULT@"): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.subscription( - sub_type, - entity, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("subscription", sub_type, entity, profile_key) def tor_infos_get(self, extra, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.tor_infos_get( - extra, - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("tor_infos_get", extra, profile_key) def tor_mode_get(self, profile_key): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) - ) - self.db_core_iface.tor_mode_get( - profile_key, - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, - ) - return fut + return self.call("tor_mode_get", profile_key) - def version_get(self): - loop = asyncio.get_running_loop() - fut = loop.create_future() - reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) - error_handler = lambda err: loop.call_soon_threadsafe( - fut.set_exception, dbus_to_bridge_exception(err) + def version_get( + self, + ): + return self.call( + "version_get", ) - self.db_core_iface.version_get( - timeout=const_TIMEOUT, - reply_handler=reply_handler, - error_handler=error_handler, + + +class AIOSignalsHandler(SignalsHandler): + + def register_signal(self, name, handler, iface="core"): + """Register an async signal handler.""" + async_handler = lambda *args: asyncio.ensure_future(handler(*args)) + return super().register_signal(name, async_handler, iface) + + async def action_launch(self, callback_id, data, profile_key="@DEFAULT@"): + return await self.call("action_launch", callback_id, data, profile_key) + + async def actions_get(self, profile_key="@DEFAULT@"): + return await self.call("actions_get", profile_key) + + async def config_get(self, section, name): + return await self.call("config_get", section, name) + + async def connect(self, profile_key="@DEFAULT@", password="", options={}): + return await self.call("connect", profile_key, password, options) + + async def contact_add(self, entity_jid, profile_key="@DEFAULT@"): + return await self.call("contact_add", entity_jid, profile_key) + + async def contact_del(self, entity_jid, profile_key="@DEFAULT@"): + return await self.call("contact_del", entity_jid, profile_key) + + async def contact_get(self, arg_0, profile_key="@DEFAULT@"): + return await self.call("contact_get", arg_0, profile_key) + + async def contact_update(self, entity_jid, name, groups, profile_key="@DEFAULT@"): + return await self.call("contact_update", entity_jid, name, groups, profile_key) + + async def contacts_get(self, profile_key="@DEFAULT@"): + return await self.call("contacts_get", profile_key) + + async def contacts_get_from_group(self, group, profile_key="@DEFAULT@"): + return await self.call("contacts_get_from_group", group, profile_key) + + async def devices_infos_get(self, bare_jid, profile_key): + return await self.call("devices_infos_get", bare_jid, profile_key) + + async def disco_find_by_features( + self, + namespaces, + identities, + bare_jid=False, + service=True, + roster=True, + own_jid=True, + local_device=False, + profile_key="@DEFAULT@", + ): + return await self.call( + "disco_find_by_features", + namespaces, + identities, + bare_jid, + service, + roster, + own_jid, + local_device, + profile_key, + ) + + async def disco_infos( + self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@" + ): + return await self.call("disco_infos", entity_jid, node, use_cache, profile_key) + + async def disco_items( + self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@" + ): + return await self.call("disco_items", entity_jid, node, use_cache, profile_key) + + async def disconnect(self, profile_key="@DEFAULT@"): + return await self.call("disconnect", profile_key) + + async def encryption_namespace_get(self, arg_0): + return await self.call("encryption_namespace_get", arg_0) + + async def encryption_plugins_get( + self, + ): + return await self.call( + "encryption_plugins_get", + ) + + async def encryption_trust_ui_get(self, to_jid, namespace, profile_key): + return await self.call("encryption_trust_ui_get", to_jid, namespace, profile_key) + + async def entities_data_get(self, jids, keys, profile): + return await self.call("entities_data_get", jids, keys, profile) + + async def entity_data_get(self, jid, keys, profile): + return await self.call("entity_data_get", jid, keys, profile) + + async def features_get(self, profile_key): + return await self.call("features_get", profile_key) + + async def history_get( + self, from_jid, to_jid, limit, between=True, filters="", profile="@NONE@" + ): + return await self.call( + "history_get", from_jid, to_jid, limit, between, filters, profile + ) + + async def image_check(self, arg_0): + return await self.call("image_check", arg_0) + + async def image_convert(self, source, dest, arg_2, extra): + return await self.call("image_convert", source, dest, arg_2, extra) + + async def image_generate_preview(self, image_path, profile_key): + return await self.call("image_generate_preview", image_path, profile_key) + + async def image_resize(self, image_path, width, height): + return await self.call("image_resize", image_path, width, height) + + async def init_pre_script( + self, + ): + return await self.call( + "init_pre_script", + ) + + async def is_connected(self, profile_key="@DEFAULT@"): + return await self.call("is_connected", profile_key) + + async def main_resource_get(self, contact_jid, profile_key="@DEFAULT@"): + return await self.call("main_resource_get", contact_jid, profile_key) + + async def menu_help_get(self, menu_id, language): + return await self.call("menu_help_get", menu_id, language) + + async def menu_launch(self, menu_type, path, data, security_limit, profile_key): + return await self.call( + "menu_launch", menu_type, path, data, security_limit, profile_key + ) + + async def menus_get(self, language, security_limit): + return await self.call("menus_get", language, security_limit) + + async def message_encryption_get(self, to_jid, profile_key): + return await self.call("message_encryption_get", to_jid, profile_key) + + async def message_encryption_start( + self, to_jid, namespace="", replace=False, profile_key="@NONE@" + ): + return await self.call( + "message_encryption_start", to_jid, namespace, replace, profile_key + ) + + async def message_encryption_stop(self, to_jid, profile_key): + return await self.call("message_encryption_stop", to_jid, profile_key) + + async def message_send( + self, + to_jid, + message, + subject={}, + mess_type="auto", + extra={}, + profile_key="@NONE@", + ): + return await self.call( + "message_send", to_jid, message, subject, mess_type, extra, profile_key + ) + + async def namespaces_get( + self, + ): + return await self.call( + "namespaces_get", + ) + + async def notification_add( + self, + type_, + body_plain, + body_rich, + title, + is_global, + requires_action, + arg_6, + priority, + expire_at, + extra, + ): + return await self.call( + "notification_add", + type_, + body_plain, + body_rich, + title, + is_global, + requires_action, + arg_6, + priority, + expire_at, + extra, + ) + + async def notification_delete(self, id_, is_global, profile_key): + return await self.call("notification_delete", id_, is_global, profile_key) + + async def notifications_expired_clean(self, limit_timestamp, profile_key): + return await self.call( + "notifications_expired_clean", limit_timestamp, profile_key + ) + + async def notifications_get(self, filters, profile_key): + return await self.call("notifications_get", filters, profile_key) + + async def param_get_a( + self, name, category, attribute="value", profile_key="@DEFAULT@" + ): + return await self.call("param_get_a", name, category, attribute, profile_key) + + async def param_get_a_async( + self, + name, + category, + attribute="value", + security_limit=-1, + profile_key="@DEFAULT@", + ): + return await self.call( + "param_get_a_async", name, category, attribute, security_limit, profile_key + ) + + async def param_set( + self, name, value, category, security_limit=-1, profile_key="@DEFAULT@" + ): + return await self.call( + "param_set", name, value, category, security_limit, profile_key + ) + + async def param_ui_get( + self, security_limit=-1, app="", extra="", profile_key="@DEFAULT@" + ): + return await self.call("param_ui_get", security_limit, app, extra, profile_key) + + async def params_categories_get( + self, + ): + return await self.call( + "params_categories_get", + ) + + async def params_register_app(self, xml, security_limit=-1, app=""): + return await self.call("params_register_app", xml, security_limit, app) + + async def params_template_load(self, filename): + return await self.call("params_template_load", filename) + + async def params_template_save(self, filename): + return await self.call("params_template_save", filename) + + async def params_values_from_category_get_async( + self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@" + ): + return await self.call( + "params_values_from_category_get_async", + category, + security_limit, + app, + extra, + profile_key, + ) + + async def presence_set( + self, to_jid="", show="", statuses={}, profile_key="@DEFAULT@" + ): + return await self.call("presence_set", to_jid, show, statuses, profile_key) + + async def presence_statuses_get(self, profile_key="@DEFAULT@"): + return await self.call("presence_statuses_get", profile_key) + + async def private_data_delete(self, namespace, key, arg_2): + return await self.call("private_data_delete", namespace, key, arg_2) + + async def private_data_get(self, namespace, key, profile_key): + return await self.call("private_data_get", namespace, key, profile_key) + + async def private_data_set(self, namespace, key, data, profile_key): + return await self.call("private_data_set", namespace, key, data, profile_key) + + async def profile_create(self, profile, password="", component=""): + return await self.call("profile_create", profile, password, component) + + async def profile_delete_async(self, profile): + return await self.call("profile_delete_async", profile) + + async def profile_is_session_started(self, profile_key="@DEFAULT@"): + return await self.call("profile_is_session_started", profile_key) + + async def profile_name_get(self, profile_key="@DEFAULT@"): + return await self.call("profile_name_get", profile_key) + + async def profile_set_default(self, profile): + return await self.call("profile_set_default", profile) + + async def profile_start_session(self, password="", profile_key="@DEFAULT@"): + return await self.call("profile_start_session", password, profile_key) + + async def profiles_list_get(self, clients=True, components=False): + return await self.call("profiles_list_get", clients, components) + + async def progress_get(self, id, profile): + return await self.call("progress_get", id, profile) + + async def progress_get_all(self, profile): + return await self.call("progress_get_all", profile) + + async def progress_get_all_metadata(self, profile): + return await self.call("progress_get_all_metadata", profile) + + async def ready_get( + self, + ): + return await self.call( + "ready_get", + ) + + async def roster_resync(self, profile_key="@DEFAULT@"): + return await self.call("roster_resync", profile_key) + + async def session_infos_get(self, profile_key): + return await self.call("session_infos_get", profile_key) + + async def sub_waiting_get(self, profile_key="@DEFAULT@"): + return await self.call("sub_waiting_get", profile_key) + + async def subscription(self, sub_type, entity, profile_key="@DEFAULT@"): + return await self.call("subscription", sub_type, entity, profile_key) + + async def tor_infos_get(self, extra, profile_key): + return await self.call("tor_infos_get", extra, profile_key) + + async def tor_mode_get(self, profile_key): + return await self.call("tor_mode_get", profile_key) + + async def version_get( + self, + ): + return await self.call( + "version_get", + ) + + +class AIOBridge(bridge): + + def __init__(self): + super().__init__() + self.signals_handler = None + + async def post_init(self): + """Post-initialization hook. + + Actually no post init is needed, but the "__getattr__" return "partial" for + unknown methods, and this causes "dynamic_import.load_and_init_bridge" to fail. + """ + pass + + def call(self, name: str, *args, **kwargs): + """Call a remote method and return an awaitable. + + @param name: name of the bridge method + """ + d = super().call(name, *args, **kwargs) + return d.asFuture(asyncio.get_event_loop()) + + async def bridge_connect(self): + """Connect to the D-Bus bridge (async version).""" + try: + self.conn = await client.connect(reactor).asFuture(asyncio.get_event_loop()) + self.db_object = await self.conn.getRemoteObject( + const_INT_PREFIX, const_OBJ_PATH + ).asFuture(asyncio.get_event_loop()) + + # Find the core and plugin interfaces + for iface in self.db_object.interfaces: + if iface.name == const_INT_PREFIX + const_CORE_SUFFIX: + self.db_core_iface = iface + elif iface.name == const_INT_PREFIX + const_PLUGIN_SUFFIX: + self.db_plugin_iface = iface + + if self.db_core_iface is None: + raise BridgeInitError( + f"Core interface {const_INT_PREFIX + const_CORE_SUFFIX} not found" + ) + if self.db_plugin_iface is None: + raise BridgeInitError( + f"Plugin interface {const_INT_PREFIX + const_PLUGIN_SUFFIX} not found" + ) + + # Initialize signals handler + self.signals_handler = AIOSignalsHandler( + self.db_object, const_INT_PREFIX + const_PLUGIN_SUFFIX + ) + except BridgeInitError as e: + raise e + except Exception as e: + msg = str(e) + if ( + "org.freedesktop.DBus.Error.ServiceUnknown" in msg + or "org.freedesktop.DBus.Error.Spawn.ExecFailed" in msg + ): + raise BridgeExceptionNoService from e + elif "org.freedesktop.DBus.Error.NotSupported" in msg: + log.error( + _( + "D-Bus is not launched, please see README to see instructions on" + " how to launch it" + ) + ) + raise BridgeInitError from e + + def register_signal(self, functionName, handler, iface="core"): + if self.signals_handler is None: + log.error("Bridge not initialized") + return + self.signals_handler.register_signal(functionName, handler, iface) + + +class TwistedBridge(bridge): + + async def post_init(self): + """Post-initialization hook. + + Actually no post init is needed, but the "__getattr__" return "partial" for + unknown methods, and this causes "dynamic_import.load_and_init_bridge" to fail. + """ + pass + + def _errback(self, failure_): + """Convert Failure to BridgeException""" + raise dbus_to_bridge_exception(failure_) + + def call(self, name, *args, **kwargs): + """Call a remote method and return a Deferred. + + @param name(str): name of the bridge method + @param args(list): arguments + @param kwargs(dict): keyword arguments (profile, etc.) + """ + return super().call(name, *args, **kwargs) + + async def bridge_connect(self) -> None: + """Connect to the D-Bus bridge.""" + return await super().bridge_connect() + + def register_signal(self, functionName, handler, iface="core"): + super().register_signal(functionName, handler, iface) + + def action_launch(self, callback_id, data, profile_key="@DEFAULT@"): + return self.call("action_launch", callback_id, data, profile_key) + + def actions_get(self, profile_key="@DEFAULT@"): + return self.call("actions_get", profile_key) + + def config_get(self, section, name): + return self.call("config_get", section, name) + + def connect(self, profile_key="@DEFAULT@", password="", options={}): + return self.call("connect", profile_key, password, options) + + def contact_add(self, entity_jid, profile_key="@DEFAULT@"): + return self.call("contact_add", entity_jid, profile_key) + + def contact_del(self, entity_jid, profile_key="@DEFAULT@"): + return self.call("contact_del", entity_jid, profile_key) + + def contact_get(self, arg_0, profile_key="@DEFAULT@"): + return self.call("contact_get", arg_0, profile_key) + + def contact_update(self, entity_jid, name, groups, profile_key="@DEFAULT@"): + return self.call("contact_update", entity_jid, name, groups, profile_key) + + def contacts_get(self, profile_key="@DEFAULT@"): + return self.call("contacts_get", profile_key) + + def contacts_get_from_group(self, group, profile_key="@DEFAULT@"): + return self.call("contacts_get_from_group", group, profile_key) + + def devices_infos_get(self, bare_jid, profile_key): + return self.call("devices_infos_get", bare_jid, profile_key) + + def disco_find_by_features( + self, + namespaces, + identities, + bare_jid=False, + service=True, + roster=True, + own_jid=True, + local_device=False, + profile_key="@DEFAULT@", + ): + return self.call( + "disco_find_by_features", + namespaces, + identities, + bare_jid, + service, + roster, + own_jid, + local_device, + profile_key, + ) + + def disco_infos(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"): + return self.call("disco_infos", entity_jid, node, use_cache, profile_key) + + def disco_items(self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"): + return self.call("disco_items", entity_jid, node, use_cache, profile_key) + + def disconnect(self, profile_key="@DEFAULT@"): + return self.call("disconnect", profile_key) + + def encryption_namespace_get(self, arg_0): + return self.call("encryption_namespace_get", arg_0) + + def encryption_plugins_get( + self, + ): + return self.call( + "encryption_plugins_get", + ) + + def encryption_trust_ui_get(self, to_jid, namespace, profile_key): + return self.call("encryption_trust_ui_get", to_jid, namespace, profile_key) + + def entities_data_get(self, jids, keys, profile): + return self.call("entities_data_get", jids, keys, profile) + + def entity_data_get(self, jid, keys, profile): + return self.call("entity_data_get", jid, keys, profile) + + def features_get(self, profile_key): + return self.call("features_get", profile_key) + + def history_get( + self, from_jid, to_jid, limit, between=True, filters="", profile="@NONE@" + ): + return self.call( + "history_get", from_jid, to_jid, limit, between, filters, profile + ) + + def image_check(self, arg_0): + return self.call("image_check", arg_0) + + def image_convert(self, source, dest, arg_2, extra): + return self.call("image_convert", source, dest, arg_2, extra) + + def image_generate_preview(self, image_path, profile_key): + return self.call("image_generate_preview", image_path, profile_key) + + def image_resize(self, image_path, width, height): + return self.call("image_resize", image_path, width, height) + + def init_pre_script( + self, + ): + return self.call( + "init_pre_script", + ) + + def is_connected(self, profile_key="@DEFAULT@"): + return self.call("is_connected", profile_key) + + def main_resource_get(self, contact_jid, profile_key="@DEFAULT@"): + return self.call("main_resource_get", contact_jid, profile_key) + + def menu_help_get(self, menu_id, language): + return self.call("menu_help_get", menu_id, language) + + def menu_launch(self, menu_type, path, data, security_limit, profile_key): + return self.call( + "menu_launch", menu_type, path, data, security_limit, profile_key + ) + + def menus_get(self, language, security_limit): + return self.call("menus_get", language, security_limit) + + def message_encryption_get(self, to_jid, profile_key): + return self.call("message_encryption_get", to_jid, profile_key) + + def message_encryption_start( + self, to_jid, namespace="", replace=False, profile_key="@NONE@" + ): + return self.call( + "message_encryption_start", to_jid, namespace, replace, profile_key + ) + + def message_encryption_stop(self, to_jid, profile_key): + return self.call("message_encryption_stop", to_jid, profile_key) + + def message_send( + self, + to_jid, + message, + subject={}, + mess_type="auto", + extra={}, + profile_key="@NONE@", + ): + return self.call( + "message_send", to_jid, message, subject, mess_type, extra, profile_key + ) + + def namespaces_get( + self, + ): + return self.call( + "namespaces_get", + ) + + def notification_add( + self, + type_, + body_plain, + body_rich, + title, + is_global, + requires_action, + arg_6, + priority, + expire_at, + extra, + ): + return self.call( + "notification_add", + type_, + body_plain, + body_rich, + title, + is_global, + requires_action, + arg_6, + priority, + expire_at, + extra, + ) + + def notification_delete(self, id_, is_global, profile_key): + return self.call("notification_delete", id_, is_global, profile_key) + + def notifications_expired_clean(self, limit_timestamp, profile_key): + return self.call("notifications_expired_clean", limit_timestamp, profile_key) + + def notifications_get(self, filters, profile_key): + return self.call("notifications_get", filters, profile_key) + + def param_get_a(self, name, category, attribute="value", profile_key="@DEFAULT@"): + return self.call("param_get_a", name, category, attribute, profile_key) + + def param_get_a_async( + self, + name, + category, + attribute="value", + security_limit=-1, + profile_key="@DEFAULT@", + ): + return self.call( + "param_get_a_async", name, category, attribute, security_limit, profile_key + ) + + def param_set( + self, name, value, category, security_limit=-1, profile_key="@DEFAULT@" + ): + return self.call("param_set", name, value, category, security_limit, profile_key) + + def param_ui_get(self, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"): + return self.call("param_ui_get", security_limit, app, extra, profile_key) + + def params_categories_get( + self, + ): + return self.call( + "params_categories_get", + ) + + def params_register_app(self, xml, security_limit=-1, app=""): + return self.call("params_register_app", xml, security_limit, app) + + def params_template_load(self, filename): + return self.call("params_template_load", filename) + + def params_template_save(self, filename): + return self.call("params_template_save", filename) + + def params_values_from_category_get_async( + self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@" + ): + return self.call( + "params_values_from_category_get_async", + category, + security_limit, + app, + extra, + profile_key, + ) + + def presence_set(self, to_jid="", show="", statuses={}, profile_key="@DEFAULT@"): + return self.call("presence_set", to_jid, show, statuses, profile_key) + + def presence_statuses_get(self, profile_key="@DEFAULT@"): + return self.call("presence_statuses_get", profile_key) + + def private_data_delete(self, namespace, key, arg_2): + return self.call("private_data_delete", namespace, key, arg_2) + + def private_data_get(self, namespace, key, profile_key): + return self.call("private_data_get", namespace, key, profile_key) + + def private_data_set(self, namespace, key, data, profile_key): + return self.call("private_data_set", namespace, key, data, profile_key) + + def profile_create(self, profile, password="", component=""): + return self.call("profile_create", profile, password, component) + + def profile_delete_async(self, profile): + return self.call("profile_delete_async", profile) + + def profile_is_session_started(self, profile_key="@DEFAULT@"): + return self.call("profile_is_session_started", profile_key) + + def profile_name_get(self, profile_key="@DEFAULT@"): + return self.call("profile_name_get", profile_key) + + def profile_set_default(self, profile): + return self.call("profile_set_default", profile) + + def profile_start_session(self, password="", profile_key="@DEFAULT@"): + return self.call("profile_start_session", password, profile_key) + + def profiles_list_get(self, clients=True, components=False): + return self.call("profiles_list_get", clients, components) + + def progress_get(self, id, profile): + return self.call("progress_get", id, profile) + + def progress_get_all(self, profile): + return self.call("progress_get_all", profile) + + def progress_get_all_metadata(self, profile): + return self.call("progress_get_all_metadata", profile) + + def ready_get( + self, + ): + return self.call( + "ready_get", + ) + + def roster_resync(self, profile_key="@DEFAULT@"): + return self.call("roster_resync", profile_key) + + def session_infos_get(self, profile_key): + return self.call("session_infos_get", profile_key) + + def sub_waiting_get(self, profile_key="@DEFAULT@"): + return self.call("sub_waiting_get", profile_key) + + def subscription(self, sub_type, entity, profile_key="@DEFAULT@"): + return self.call("subscription", sub_type, entity, profile_key) + + def tor_infos_get(self, extra, profile_key): + return self.call("tor_infos_get", extra, profile_key) + + def tor_mode_get(self, profile_key): + return self.call("tor_mode_get", profile_key) + + def version_get( + self, + ): + return self.call( + "version_get", ) - return fut