diff libervia/backend/bridge/bridge_constructor/constructors/dbus/constructor.py @ 4071:4b842c1fb686

refactoring: renamed `sat` package to `libervia.backend`
author Goffi <goffi@goffi.org>
date Fri, 02 Jun 2023 11:49:51 +0200
parents sat/bridge/bridge_constructor/constructors/dbus/constructor.py@524856bd7b19
children 0d7bb4df2343
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libervia/backend/bridge/bridge_constructor/constructors/dbus/constructor.py	Fri Jun 02 11:49:51 2023 +0200
@@ -0,0 +1,118 @@
+#!/usr/bin/env python3
+
+
+# Libervia: an XMPP client
+# Copyright (C) 2009-2021 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 libervia.backend.bridge.bridge_constructor import base_constructor
+
+
+class DbusConstructor(base_constructor.Constructor):
+    NAME = "dbus"
+    CORE_TEMPLATE = "dbus_core_template.py"
+    CORE_DEST = "dbus_bridge.py"
+    CORE_FORMATS = {
+        "methods_declarations": """\
+        Method('{name}', arguments='{sig_in}', returns='{sig_out}'),""",
+
+        "methods": """\
+    def dbus_{name}(self, {args}):
+        {debug}return self._callback("{name}", {args_no_default})\n""",
+
+        "signals_declarations": """\
+        Signal('{name}', '{sig_in}'),""",
+
+        "signals": """\
+    def {name}(self, {args}):
+        self._obj.emitSignal("{name}", {args})\n""",
+    }
+
+    FRONTEND_TEMPLATE = "dbus_frontend_template.py"
+    FRONTEND_DEST = CORE_DEST
+    FRONTEND_FORMATS = {
+        "methods": """\
+    def {name}(self, {args}{async_comma}{async_args}):
+        {error_handler}{blocking_call}{debug}return {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""",
+    }
+
+    def core_completion_signal(self, completion, function, default, arg_doc, async_):
+        completion["category"] = completion["category"].upper()
+        completion["body"] = (
+            "pass"
+            if not self.args.debug
+            else 'log.debug ("{}")'.format(completion["name"])
+        )
+
+    def core_completion_method(self, completion, function, default, arg_doc, async_):
+        completion.update(
+            {
+                "debug": (
+                    "" if not self.args.debug
+                    else f'log.debug ("{completion["name"]}")\n{8 * " "}'
+                )
+            }
+        )
+
+    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