diff sat/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py @ 3042:964abd07dc03

bridge (dbus): AsyncIO version of D-Bus bridge: The frontends D-Bus bridge has now an AIOBridge version which can be instantiated to use asyncio (the loop must be managed by frontends).
author Goffi <goffi@goffi.org>
date Tue, 01 Oct 2019 22:49:10 +0200
parents ab2696e34d29
children 9d0df638c8b4
line wrap: on
line diff
--- a/sat/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py	Tue Oct 01 22:49:06 2019 +0200
+++ b/sat/bridge/bridge_constructor/constructors/dbus/dbus_frontend_template.py	Tue Oct 01 22:49:10 2019 +0200
@@ -17,17 +17,18 @@
 # 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 sat.core.i18n import _
-from bridge_frontend import BridgeException
+import asyncio
 import dbus
+import ast
+from sat.core.i18n import _
+from .bridge_frontend import BridgeException
 from sat.core.log import getLogger
-log = getLogger(__name__)
 from sat.core.exceptions import BridgeExceptionNoService, BridgeInitError
+from dbus.mainloop.glib import DBusGMainLoop
 
-from dbus.mainloop.glib import DBusGMainLoop
 DBusGMainLoop(set_as_default=True)
+log = getLogger(__name__)
 
-import ast
 
 const_INT_PREFIX = "org.salutatoi.SAT"  # Interface prefix
 const_ERROR_PREFIX = const_INT_PREFIX + ".error"
@@ -59,7 +60,7 @@
     return BridgeException(name, message, condition)
 
 
-class Bridge(object):
+class Bridge:
 
     def bridgeConnect(self, callback, errback):
         try:
@@ -79,7 +80,8 @@
                 errback(BridgeInitError)
             else:
                 errback(e)
-        callback()
+        else:
+            callback()
         #props = self.db_core_iface.getProperties()
 
     def register_signal(self, functionName, handler, iface="core"):
@@ -137,3 +139,46 @@
             return getPluginMethod
 
 ##METHODS_PART##
+
+class AIOBridge(Bridge):
+
+    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 getPluginMethod(*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))
+                method(
+                    *args,
+                    **kwargs,
+                    timeout=const_TIMEOUT,
+                    reply_handler=reply_handler,
+                    error_handler=error_handler
+                )
+                return fut
+
+            return getPluginMethod
+
+    def bridgeConnect(self):
+        loop = asyncio.get_running_loop()
+        fut = loop.create_future()
+        super().bridgeConnect(
+            callback=lambda: loop.call_soon_threadsafe(fut.set_result, None),
+            errback=lambda e: loop.call_soon_threadsafe(fut.set_exception, e)
+        )
+        return fut
+
+##ASYNC_METHODS_PART##