- Add a 5s timeout on connection to avoid infinite hang when socket is not working. - Raise `BridgeInitError` on time-out (needed to make `auto` bridge fallback correctly).
758 lines
28 KiB
Python
758 lines
28 KiB
Python
#!/usr/bin/env python3
|
|
|
|
# Libervia 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
|
|
# the Free Software Foundation, either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU Affero General Public License for more details.
|
|
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
from types import MethodType
|
|
from functools import partialmethod
|
|
from twisted.internet import defer, reactor
|
|
from libervia.backend.core.i18n import _
|
|
from libervia.backend.core.log import getLogger
|
|
from libervia.backend.core.exceptions import BridgeInitError
|
|
from libervia.backend.tools import config
|
|
from txdbus import client, objects, error
|
|
from txdbus.interface import DBusInterface, Method, Signal
|
|
|
|
log = getLogger(__name__)
|
|
|
|
# Interface prefix
|
|
conf = config.parse_main_conf()
|
|
bridge_conf = conf.get_bridge_conf(config.DBusBridgeSettings)
|
|
const_INT_PREFIX = bridge_conf.int_prefix
|
|
const_ERROR_PREFIX = const_INT_PREFIX + ".error"
|
|
const_OBJ_PATH = "/org/libervia/Libervia/bridge"
|
|
const_CORE_SUFFIX = ".core"
|
|
const_PLUGIN_SUFFIX = ".plugin"
|
|
const_CONNECT_TIMEOUT = 5
|
|
|
|
|
|
class ParseError(Exception):
|
|
pass
|
|
|
|
|
|
class DBusException(Exception):
|
|
pass
|
|
|
|
|
|
class MethodNotRegistered(DBusException):
|
|
dbusErrorName = const_ERROR_PREFIX + ".MethodNotRegistered"
|
|
|
|
|
|
class GenericException(DBusException):
|
|
def __init__(self, twisted_error):
|
|
"""
|
|
|
|
@param twisted_error (Failure): instance of twisted Failure
|
|
error message is used to store a repr of message and condition in a tuple,
|
|
so it can be evaluated by the frontend bridge.
|
|
"""
|
|
try:
|
|
# twisted_error.value is a class
|
|
class_ = twisted_error.value().__class__
|
|
except TypeError:
|
|
# twisted_error.value is an instance
|
|
class_ = twisted_error.value.__class__
|
|
data = twisted_error.getErrorMessage()
|
|
try:
|
|
data = (data, twisted_error.value.condition)
|
|
except AttributeError:
|
|
data = (data,)
|
|
else:
|
|
data = (str(twisted_error),)
|
|
self.dbusErrorName = ".".join(
|
|
(const_ERROR_PREFIX, class_.__module__, class_.__name__)
|
|
)
|
|
super(GenericException, self).__init__(repr(data))
|
|
|
|
@classmethod
|
|
def create_and_raise(cls, exc):
|
|
raise cls(exc)
|
|
|
|
|
|
class DBusObject(objects.DBusObject):
|
|
|
|
core_iface = DBusInterface(
|
|
const_INT_PREFIX + const_CORE_SUFFIX,
|
|
Method("action_launch", arguments="sss", returns="s"),
|
|
Method("actions_get", arguments="s", returns="a(ssi)"),
|
|
Method("config_get", arguments="ss", returns="s"),
|
|
Method("connect", arguments="ssa{ss}", returns="b"),
|
|
Method("contact_add", arguments="ss", returns=""),
|
|
Method("contact_del", arguments="ss", returns=""),
|
|
Method("contact_get", arguments="ss", returns="(a{ss}as)"),
|
|
Method("contact_update", arguments="ssass", returns=""),
|
|
Method("contacts_get", arguments="s", returns="a(sa{ss}as)"),
|
|
Method("contacts_get_from_group", arguments="ss", returns="as"),
|
|
Method("devices_infos_get", arguments="ss", returns="s"),
|
|
Method(
|
|
"disco_find_by_features",
|
|
arguments="asa(ss)bbbbbs",
|
|
returns="(a{sa(ssss)}a{sa(ssss)}a{sa(ssss)})",
|
|
),
|
|
Method("disco_infos", arguments="ssbs", returns="(asa(ssss)a{sa(a{ss}as)})"),
|
|
Method("disco_items", arguments="ssbs", returns="a(sss)"),
|
|
Method("disconnect", arguments="s", returns=""),
|
|
Method("encryption_namespace_get", arguments="s", returns="s"),
|
|
Method("encryption_plugins_get", arguments="", returns="s"),
|
|
Method("encryption_trust_ui_get", arguments="sss", returns="s"),
|
|
Method("entities_data_get", arguments="asass", returns="a{sa{ss}}"),
|
|
Method("entity_data_get", arguments="sass", returns="a{ss}"),
|
|
Method("features_get", arguments="s", returns="a{sa{ss}}"),
|
|
Method("history_get", arguments="ssiba{ss}s", returns="a(sdssa{ss}a{ss}ss)"),
|
|
Method("history_last_messages_metadata_get", arguments="ss", returns="s"),
|
|
Method("image_check", arguments="s", returns="s"),
|
|
Method("image_convert", arguments="ssss", returns="s"),
|
|
Method("image_generate_preview", arguments="ss", returns="s"),
|
|
Method("image_resize", arguments="sii", returns="s"),
|
|
Method("init_pre_script", arguments="", returns=""),
|
|
Method("is_connected", arguments="s", returns="b"),
|
|
Method("main_resource_get", arguments="ss", returns="s"),
|
|
Method("menu_help_get", arguments="ss", returns="s"),
|
|
Method("menu_launch", arguments="sasa{ss}is", returns="a{ss}"),
|
|
Method("menus_get", arguments="si", returns="a(ssasasa{ss})"),
|
|
Method("message_encryption_get", arguments="ss", returns="s"),
|
|
Method("message_encryption_start", arguments="ssbs", returns=""),
|
|
Method("message_encryption_stop", arguments="ss", returns=""),
|
|
Method("message_send", arguments="sa{ss}a{ss}sss", returns=""),
|
|
Method("messages_display_state_get", arguments="ass", returns="s"),
|
|
Method("messages_display_state_set", arguments="sss", returns=""),
|
|
Method("namespaces_get", arguments="", returns="a{ss}"),
|
|
Method("notification_add", arguments="ssssbbsdss", returns=""),
|
|
Method("notification_delete", arguments="sbs", returns=""),
|
|
Method("notifications_expired_clean", arguments="ds", returns=""),
|
|
Method("notifications_get", arguments="ss", returns="s"),
|
|
Method("param_get_a", arguments="ssss", returns="s"),
|
|
Method("param_get_a_async", arguments="sssis", returns="s"),
|
|
Method("param_set", arguments="sssis", returns=""),
|
|
Method("param_ui_get", arguments="isss", returns="s"),
|
|
Method("params_categories_get", arguments="", returns="as"),
|
|
Method("params_register_app", arguments="sis", returns=""),
|
|
Method("params_template_load", arguments="s", returns="b"),
|
|
Method("params_template_save", arguments="s", returns="b"),
|
|
Method(
|
|
"params_values_from_category_get_async", arguments="sisss", returns="a{ss}"
|
|
),
|
|
Method("presence_set", arguments="ssa{ss}s", returns=""),
|
|
Method("presence_statuses_get", arguments="s", returns="a{sa{s(sia{ss})}}"),
|
|
Method("private_data_delete", arguments="sss", returns=""),
|
|
Method("private_data_get", arguments="sss", returns="s"),
|
|
Method("private_data_set", arguments="ssss", returns=""),
|
|
Method("profile_create", arguments="sss", returns=""),
|
|
Method("profile_delete_async", arguments="s", returns=""),
|
|
Method("profile_is_session_started", arguments="s", returns="b"),
|
|
Method("profile_name_get", arguments="s", returns="s"),
|
|
Method("profile_set_default", arguments="s", returns=""),
|
|
Method("profile_start_session", arguments="ss", returns="b"),
|
|
Method("profiles_list_get", arguments="bb", returns="as"),
|
|
Method("progress_get", arguments="ss", returns="a{ss}"),
|
|
Method("progress_get_all", arguments="s", returns="a{sa{sa{ss}}}"),
|
|
Method("progress_get_all_metadata", arguments="s", returns="a{sa{sa{ss}}}"),
|
|
Method("ready_get", arguments="", returns=""),
|
|
Method("roster_resync", arguments="s", returns=""),
|
|
Method("session_infos_get", arguments="s", returns="a{ss}"),
|
|
Method("sub_waiting_get", arguments="s", returns="a{ss}"),
|
|
Method("subscription", arguments="sss", returns=""),
|
|
Method("tor_infos_get", arguments="ss", returns="s"),
|
|
Method("tor_mode_get", arguments="s", returns="s"),
|
|
Method("version_get", arguments="", returns="s"),
|
|
Signal("_debug", "sa{ss}s"),
|
|
Signal("action_new", "ssis"),
|
|
Signal("connected", "ss"),
|
|
Signal("contact_deleted", "ss"),
|
|
Signal("contact_new", "sa{ss}ass"),
|
|
Signal("disconnected", "s"),
|
|
Signal("entity_data_updated", "ssss"),
|
|
Signal("message_encryption_started", "sss"),
|
|
Signal("message_encryption_stopped", "sa{ss}s"),
|
|
Signal("message_new", "sdssa{ss}a{ss}sss"),
|
|
Signal("message_update", "ssss"),
|
|
Signal("messages_display_state_reset", "ss"),
|
|
Signal("messages_new", "a(sdssa{ss}a{ss}sss)s"),
|
|
Signal("notification_deleted", "ss"),
|
|
Signal("notification_new", "sdssssbidss"),
|
|
Signal("param_update", "ssss"),
|
|
Signal("presence_update", "ssia{ss}s"),
|
|
Signal("profile_connection_error", "ss"),
|
|
Signal("profile_ready", "s"),
|
|
Signal("progress_error", "sss"),
|
|
Signal("progress_finished", "sa{ss}s"),
|
|
Signal("progress_started", "sa{ss}s"),
|
|
Signal("subscribe", "sss"),
|
|
)
|
|
plugin_iface = DBusInterface(const_INT_PREFIX + const_PLUGIN_SUFFIX)
|
|
|
|
dbusInterfaces = [core_iface, plugin_iface]
|
|
|
|
def __init__(self, path):
|
|
super().__init__(path)
|
|
log.debug("Init DBusObject...")
|
|
self.cb = {}
|
|
|
|
def register_method(self, name, cb):
|
|
self.cb[name] = cb
|
|
|
|
def _callback(self, name, *args, **kwargs):
|
|
"""Call the callback if it exists, raise an exception else"""
|
|
try:
|
|
cb = self.cb[name]
|
|
except KeyError:
|
|
raise MethodNotRegistered
|
|
else:
|
|
d = defer.maybeDeferred(cb, *args, **kwargs)
|
|
d.addErrback(GenericException.create_and_raise)
|
|
return d
|
|
|
|
def dbus_action_launch(self, callback_id, data, profile_key="@DEFAULT@"):
|
|
return self._callback("action_launch", callback_id, data, profile_key)
|
|
|
|
def dbus_actions_get(self, profile_key="@DEFAULT@"):
|
|
return self._callback("actions_get", profile_key)
|
|
|
|
def dbus_config_get(self, section, name):
|
|
return self._callback("config_get", section, name)
|
|
|
|
def dbus_connect(self, profile_key="@DEFAULT@", password="", options={}):
|
|
return self._callback("connect", profile_key, password, options)
|
|
|
|
def dbus_contact_add(self, entity_jid, profile_key="@DEFAULT@"):
|
|
return self._callback("contact_add", entity_jid, profile_key)
|
|
|
|
def dbus_contact_del(self, entity_jid, profile_key="@DEFAULT@"):
|
|
return self._callback("contact_del", entity_jid, profile_key)
|
|
|
|
def dbus_contact_get(self, arg_0, profile_key="@DEFAULT@"):
|
|
return self._callback("contact_get", arg_0, profile_key)
|
|
|
|
def dbus_contact_update(self, entity_jid, name, groups, profile_key="@DEFAULT@"):
|
|
return self._callback("contact_update", entity_jid, name, groups, profile_key)
|
|
|
|
def dbus_contacts_get(self, profile_key="@DEFAULT@"):
|
|
return self._callback("contacts_get", profile_key)
|
|
|
|
def dbus_contacts_get_from_group(self, group, profile_key="@DEFAULT@"):
|
|
return self._callback("contacts_get_from_group", group, profile_key)
|
|
|
|
def dbus_devices_infos_get(self, bare_jid, profile_key):
|
|
return self._callback("devices_infos_get", bare_jid, profile_key)
|
|
|
|
def dbus_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._callback(
|
|
"disco_find_by_features",
|
|
namespaces,
|
|
identities,
|
|
bare_jid,
|
|
service,
|
|
roster,
|
|
own_jid,
|
|
local_device,
|
|
profile_key,
|
|
)
|
|
|
|
def dbus_disco_infos(
|
|
self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"
|
|
):
|
|
return self._callback("disco_infos", entity_jid, node, use_cache, profile_key)
|
|
|
|
def dbus_disco_items(
|
|
self, entity_jid, node="", use_cache=True, profile_key="@DEFAULT@"
|
|
):
|
|
return self._callback("disco_items", entity_jid, node, use_cache, profile_key)
|
|
|
|
def dbus_disconnect(self, profile_key="@DEFAULT@"):
|
|
return self._callback("disconnect", profile_key)
|
|
|
|
def dbus_encryption_namespace_get(self, arg_0):
|
|
return self._callback("encryption_namespace_get", arg_0)
|
|
|
|
def dbus_encryption_plugins_get(
|
|
self,
|
|
):
|
|
return self._callback(
|
|
"encryption_plugins_get",
|
|
)
|
|
|
|
def dbus_encryption_trust_ui_get(self, to_jid, namespace, profile_key):
|
|
return self._callback("encryption_trust_ui_get", to_jid, namespace, profile_key)
|
|
|
|
def dbus_entities_data_get(self, jids, keys, profile):
|
|
return self._callback("entities_data_get", jids, keys, profile)
|
|
|
|
def dbus_entity_data_get(self, jid, keys, profile):
|
|
return self._callback("entity_data_get", jid, keys, profile)
|
|
|
|
def dbus_features_get(self, profile_key):
|
|
return self._callback("features_get", profile_key)
|
|
|
|
def dbus_history_get(
|
|
self, from_jid, to_jid, limit, between=True, filters="", profile="@NONE@"
|
|
):
|
|
return self._callback(
|
|
"history_get", from_jid, to_jid, limit, between, filters, profile
|
|
)
|
|
|
|
def dbus_history_last_messages_metadata_get(self, options, profile_key="@NONE@"):
|
|
return self._callback("history_last_messages_metadata_get", options, profile_key)
|
|
|
|
def dbus_image_check(self, arg_0):
|
|
return self._callback("image_check", arg_0)
|
|
|
|
def dbus_image_convert(self, source, dest, arg_2, extra):
|
|
return self._callback("image_convert", source, dest, arg_2, extra)
|
|
|
|
def dbus_image_generate_preview(self, image_path, profile_key):
|
|
return self._callback("image_generate_preview", image_path, profile_key)
|
|
|
|
def dbus_image_resize(self, image_path, width, height):
|
|
return self._callback("image_resize", image_path, width, height)
|
|
|
|
def dbus_init_pre_script(
|
|
self,
|
|
):
|
|
return self._callback(
|
|
"init_pre_script",
|
|
)
|
|
|
|
def dbus_is_connected(self, profile_key="@DEFAULT@"):
|
|
return self._callback("is_connected", profile_key)
|
|
|
|
def dbus_main_resource_get(self, contact_jid, profile_key="@DEFAULT@"):
|
|
return self._callback("main_resource_get", contact_jid, profile_key)
|
|
|
|
def dbus_menu_help_get(self, menu_id, language):
|
|
return self._callback("menu_help_get", menu_id, language)
|
|
|
|
def dbus_menu_launch(self, menu_type, path, data, security_limit, profile_key):
|
|
return self._callback(
|
|
"menu_launch", menu_type, path, data, security_limit, profile_key
|
|
)
|
|
|
|
def dbus_menus_get(self, language, security_limit):
|
|
return self._callback("menus_get", language, security_limit)
|
|
|
|
def dbus_message_encryption_get(self, to_jid, profile_key):
|
|
return self._callback("message_encryption_get", to_jid, profile_key)
|
|
|
|
def dbus_message_encryption_start(
|
|
self, to_jid, namespace="", replace=False, profile_key="@NONE@"
|
|
):
|
|
return self._callback(
|
|
"message_encryption_start", to_jid, namespace, replace, profile_key
|
|
)
|
|
|
|
def dbus_message_encryption_stop(self, to_jid, profile_key):
|
|
return self._callback("message_encryption_stop", to_jid, profile_key)
|
|
|
|
def dbus_message_send(
|
|
self,
|
|
to_jid,
|
|
message,
|
|
subject={},
|
|
mess_type="auto",
|
|
extra={},
|
|
profile_key="@NONE@",
|
|
):
|
|
return self._callback(
|
|
"message_send", to_jid, message, subject, mess_type, extra, profile_key
|
|
)
|
|
|
|
def dbus_messages_display_state_get(self, jids, profile_key):
|
|
return self._callback("messages_display_state_get", jids, profile_key)
|
|
|
|
def dbus_messages_display_state_set(self, peer_jid, message_uid, profile_key):
|
|
return self._callback(
|
|
"messages_display_state_set", peer_jid, message_uid, profile_key
|
|
)
|
|
|
|
def dbus_namespaces_get(
|
|
self,
|
|
):
|
|
return self._callback(
|
|
"namespaces_get",
|
|
)
|
|
|
|
def dbus_notification_add(
|
|
self,
|
|
type_,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
is_global,
|
|
requires_action,
|
|
arg_6,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
):
|
|
return self._callback(
|
|
"notification_add",
|
|
type_,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
is_global,
|
|
requires_action,
|
|
arg_6,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
)
|
|
|
|
def dbus_notification_delete(self, id_, is_global, profile_key):
|
|
return self._callback("notification_delete", id_, is_global, profile_key)
|
|
|
|
def dbus_notifications_expired_clean(self, limit_timestamp, profile_key):
|
|
return self._callback("notifications_expired_clean", limit_timestamp, profile_key)
|
|
|
|
def dbus_notifications_get(self, filters, profile_key):
|
|
return self._callback("notifications_get", filters, profile_key)
|
|
|
|
def dbus_param_get_a(
|
|
self, name, category, attribute="value", profile_key="@DEFAULT@"
|
|
):
|
|
return self._callback("param_get_a", name, category, attribute, profile_key)
|
|
|
|
def dbus_param_get_a_async(
|
|
self,
|
|
name,
|
|
category,
|
|
attribute="value",
|
|
security_limit=-1,
|
|
profile_key="@DEFAULT@",
|
|
):
|
|
return self._callback(
|
|
"param_get_a_async", name, category, attribute, security_limit, profile_key
|
|
)
|
|
|
|
def dbus_param_set(
|
|
self, name, value, category, security_limit=-1, profile_key="@DEFAULT@"
|
|
):
|
|
return self._callback(
|
|
"param_set", name, value, category, security_limit, profile_key
|
|
)
|
|
|
|
def dbus_param_ui_get(
|
|
self, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"
|
|
):
|
|
return self._callback("param_ui_get", security_limit, app, extra, profile_key)
|
|
|
|
def dbus_params_categories_get(
|
|
self,
|
|
):
|
|
return self._callback(
|
|
"params_categories_get",
|
|
)
|
|
|
|
def dbus_params_register_app(self, xml, security_limit=-1, app=""):
|
|
return self._callback("params_register_app", xml, security_limit, app)
|
|
|
|
def dbus_params_template_load(self, filename):
|
|
return self._callback("params_template_load", filename)
|
|
|
|
def dbus_params_template_save(self, filename):
|
|
return self._callback("params_template_save", filename)
|
|
|
|
def dbus_params_values_from_category_get_async(
|
|
self, category, security_limit=-1, app="", extra="", profile_key="@DEFAULT@"
|
|
):
|
|
return self._callback(
|
|
"params_values_from_category_get_async",
|
|
category,
|
|
security_limit,
|
|
app,
|
|
extra,
|
|
profile_key,
|
|
)
|
|
|
|
def dbus_presence_set(self, to_jid="", show="", statuses={}, profile_key="@DEFAULT@"):
|
|
return self._callback("presence_set", to_jid, show, statuses, profile_key)
|
|
|
|
def dbus_presence_statuses_get(self, profile_key="@DEFAULT@"):
|
|
return self._callback("presence_statuses_get", profile_key)
|
|
|
|
def dbus_private_data_delete(self, namespace, key, arg_2):
|
|
return self._callback("private_data_delete", namespace, key, arg_2)
|
|
|
|
def dbus_private_data_get(self, namespace, key, profile_key):
|
|
return self._callback("private_data_get", namespace, key, profile_key)
|
|
|
|
def dbus_private_data_set(self, namespace, key, data, profile_key):
|
|
return self._callback("private_data_set", namespace, key, data, profile_key)
|
|
|
|
def dbus_profile_create(self, profile, password="", component=""):
|
|
return self._callback("profile_create", profile, password, component)
|
|
|
|
def dbus_profile_delete_async(self, profile):
|
|
return self._callback("profile_delete_async", profile)
|
|
|
|
def dbus_profile_is_session_started(self, profile_key="@DEFAULT@"):
|
|
return self._callback("profile_is_session_started", profile_key)
|
|
|
|
def dbus_profile_name_get(self, profile_key="@DEFAULT@"):
|
|
return self._callback("profile_name_get", profile_key)
|
|
|
|
def dbus_profile_set_default(self, profile):
|
|
return self._callback("profile_set_default", profile)
|
|
|
|
def dbus_profile_start_session(self, password="", profile_key="@DEFAULT@"):
|
|
return self._callback("profile_start_session", password, profile_key)
|
|
|
|
def dbus_profiles_list_get(self, clients=True, components=False):
|
|
return self._callback("profiles_list_get", clients, components)
|
|
|
|
def dbus_progress_get(self, id, profile):
|
|
return self._callback("progress_get", id, profile)
|
|
|
|
def dbus_progress_get_all(self, profile):
|
|
return self._callback("progress_get_all", profile)
|
|
|
|
def dbus_progress_get_all_metadata(self, profile):
|
|
return self._callback("progress_get_all_metadata", profile)
|
|
|
|
def dbus_ready_get(
|
|
self,
|
|
):
|
|
return self._callback(
|
|
"ready_get",
|
|
)
|
|
|
|
def dbus_roster_resync(self, profile_key="@DEFAULT@"):
|
|
return self._callback("roster_resync", profile_key)
|
|
|
|
def dbus_session_infos_get(self, profile_key):
|
|
return self._callback("session_infos_get", profile_key)
|
|
|
|
def dbus_sub_waiting_get(self, profile_key="@DEFAULT@"):
|
|
return self._callback("sub_waiting_get", profile_key)
|
|
|
|
def dbus_subscription(self, sub_type, entity, profile_key="@DEFAULT@"):
|
|
return self._callback("subscription", sub_type, entity, profile_key)
|
|
|
|
def dbus_tor_infos_get(self, extra, profile_key):
|
|
return self._callback("tor_infos_get", extra, profile_key)
|
|
|
|
def dbus_tor_mode_get(self, profile_key):
|
|
return self._callback("tor_mode_get", profile_key)
|
|
|
|
def dbus_version_get(
|
|
self,
|
|
):
|
|
return self._callback(
|
|
"version_get",
|
|
)
|
|
|
|
|
|
class bridge:
|
|
|
|
def __init__(self):
|
|
log.info("Init DBus...")
|
|
self._obj = DBusObject(const_OBJ_PATH)
|
|
|
|
async def post_init(self):
|
|
try:
|
|
d = client.connect(reactor)
|
|
reactor.callLater(const_CONNECT_TIMEOUT, d.cancel)
|
|
|
|
def on_cancel(failure):
|
|
if failure.check(defer.CancelledError):
|
|
log.error(
|
|
f"D-Bus connection timed out after {const_CONNECT_TIMEOUT} s, "
|
|
"please check the D-Bus service"
|
|
)
|
|
return failure
|
|
|
|
d.addErrback(on_cancel)
|
|
self.conn = await d
|
|
except defer.CancelledError:
|
|
# The connect deferred was cancelled by the timeout, we raise BridgeInitError
|
|
# so that the "auto" bridge can fall back to the next one.
|
|
raise BridgeInitError from None
|
|
except error.DBusException as e:
|
|
if e.errName == "org.freedesktop.DBus.Error.NotSupported":
|
|
log.error(
|
|
_(
|
|
"D-Bus is not launched, please see README to see instructions on "
|
|
"how to launch it"
|
|
)
|
|
)
|
|
raise BridgeInitError(str(e))
|
|
|
|
async def export(self):
|
|
self.conn.exportObject(self._obj)
|
|
await self.conn.requestBusName(const_INT_PREFIX)
|
|
|
|
def _debug(self, action, params, profile):
|
|
self._obj.emitSignal("_debug", action, params, profile)
|
|
|
|
def action_new(self, action_data, id, security_limit, profile):
|
|
self._obj.emitSignal("action_new", action_data, id, security_limit, profile)
|
|
|
|
def connected(self, jid_s, profile):
|
|
self._obj.emitSignal("connected", jid_s, profile)
|
|
|
|
def contact_deleted(self, entity_jid, profile):
|
|
self._obj.emitSignal("contact_deleted", entity_jid, profile)
|
|
|
|
def contact_new(self, contact_jid, attributes, groups, profile):
|
|
self._obj.emitSignal("contact_new", contact_jid, attributes, groups, profile)
|
|
|
|
def disconnected(self, profile):
|
|
self._obj.emitSignal("disconnected", profile)
|
|
|
|
def entity_data_updated(self, jid, name, value, profile):
|
|
self._obj.emitSignal("entity_data_updated", jid, name, value, profile)
|
|
|
|
def message_encryption_started(self, to_jid, encryption_data, profile_key):
|
|
self._obj.emitSignal(
|
|
"message_encryption_started", to_jid, encryption_data, profile_key
|
|
)
|
|
|
|
def message_encryption_stopped(self, to_jid, encryption_data, profile_key):
|
|
self._obj.emitSignal(
|
|
"message_encryption_stopped", to_jid, encryption_data, profile_key
|
|
)
|
|
|
|
def message_new(
|
|
self,
|
|
uid,
|
|
timestamp,
|
|
from_jid,
|
|
to_jid,
|
|
message,
|
|
subject,
|
|
mess_type,
|
|
extra,
|
|
profile,
|
|
):
|
|
self._obj.emitSignal(
|
|
"message_new",
|
|
uid,
|
|
timestamp,
|
|
from_jid,
|
|
to_jid,
|
|
message,
|
|
subject,
|
|
mess_type,
|
|
extra,
|
|
profile,
|
|
)
|
|
|
|
def message_update(self, uid, message_type, message_data, profile):
|
|
self._obj.emitSignal("message_update", uid, message_type, message_data, profile)
|
|
|
|
def messages_display_state_reset(self, peer_jid, profile):
|
|
self._obj.emitSignal("messages_display_state_reset", peer_jid, profile)
|
|
|
|
def messages_new(self, messages, profile):
|
|
self._obj.emitSignal("messages_new", messages, profile)
|
|
|
|
def notification_deleted(self, id, profile):
|
|
self._obj.emitSignal("notification_deleted", id, profile)
|
|
|
|
def notification_new(
|
|
self,
|
|
id,
|
|
timestamp,
|
|
type,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
requires_action,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
profile,
|
|
):
|
|
self._obj.emitSignal(
|
|
"notification_new",
|
|
id,
|
|
timestamp,
|
|
type,
|
|
body_plain,
|
|
body_rich,
|
|
title,
|
|
requires_action,
|
|
priority,
|
|
expire_at,
|
|
extra,
|
|
profile,
|
|
)
|
|
|
|
def param_update(self, name, value, category, profile):
|
|
self._obj.emitSignal("param_update", name, value, category, profile)
|
|
|
|
def presence_update(self, entity_jid, show, priority, statuses, profile):
|
|
self._obj.emitSignal(
|
|
"presence_update", entity_jid, show, priority, statuses, profile
|
|
)
|
|
|
|
def profile_connection_error(self, error, profile):
|
|
self._obj.emitSignal("profile_connection_error", error, profile)
|
|
|
|
def profile_ready(self, profile):
|
|
self._obj.emitSignal("profile_ready", profile)
|
|
|
|
def progress_error(self, id, error, profile):
|
|
self._obj.emitSignal("progress_error", id, error, profile)
|
|
|
|
def progress_finished(self, id, metadata, profile):
|
|
self._obj.emitSignal("progress_finished", id, metadata, profile)
|
|
|
|
def progress_started(self, id, metadata, profile):
|
|
self._obj.emitSignal("progress_started", id, metadata, profile)
|
|
|
|
def subscribe(self, sub_type, entity_jid, profile):
|
|
self._obj.emitSignal("subscribe", sub_type, entity_jid, profile)
|
|
|
|
def register_method(self, name, callback):
|
|
log.debug(f"registering DBus bridge method [{name}]")
|
|
self._obj.register_method(name, callback)
|
|
|
|
def emit_signal(self, name, *args):
|
|
self._obj.emitSignal(name, *args)
|
|
|
|
def add_method(
|
|
self, name, int_suffix, in_sign, out_sign, method, async_=False, doc={}
|
|
):
|
|
"""Dynamically add a method to D-Bus bridge"""
|
|
# FIXME: doc parameter is kept only temporary, the time to remove it from calls
|
|
log.debug(f"Adding method {name!r} to D-Bus bridge")
|
|
self._obj.plugin_iface.addMethod(
|
|
Method(name, arguments=in_sign, returns=out_sign)
|
|
)
|
|
|
|
# we have to create a method here instead of using partialmethod, because txdbus
|
|
# uses __func__ which doesn't work with partialmethod
|
|
def caller(self_, *args, **kwargs):
|
|
return self_._callback(name, *args, **kwargs)
|
|
|
|
setattr(self._obj, f"dbus_{name}", MethodType(caller, self._obj))
|
|
self.register_method(name, method)
|
|
|
|
def add_signal(self, name, int_suffix, signature, doc={}):
|
|
"""Dynamically add a signal to D-Bus bridge"""
|
|
log.debug(f"Adding signal {name!r} to D-Bus bridge")
|
|
self._obj.plugin_iface.addSignal(Signal(name, signature))
|
|
setattr(bridge, name, partialmethod(bridge.emit_signal, name))
|