quick_frontend: Q&D adapter to use legacy callback/errback with modern bridges
This commit is contained in:
parent
e8b3948ad0
commit
d3dc59b141
3 changed files with 134 additions and 4 deletions
|
|
@ -349,7 +349,12 @@ class QuickApp:
|
|||
log.warning(_("Can't retrieve encryption plugins: {msg}").format(msg=failure_))
|
||||
|
||||
def on_bridge_connected(self):
|
||||
self.bridge.ready_get(self.on_backend_ready)
|
||||
d = self.bridge.ready_get()
|
||||
d.addErrback(self._ready_get_eb)
|
||||
d.addCallback(lambda __: self.on_backend_ready())
|
||||
|
||||
def _ready_get_eb(self, failure_):
|
||||
log.error("Can't check backend readiness: {msg}".format(msg=failure_))
|
||||
|
||||
def _bridge_cb(self):
|
||||
self.register_signal("connected")
|
||||
|
|
|
|||
118
libervia/frontends/quick_frontend/quick_bridge.py
Normal file
118
libervia/frontends/quick_frontend/quick_bridge.py
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
# Libervia: an XMPP client
|
||||
# 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/>.
|
||||
|
||||
"""Adapte the legacy callback/errback bridge API to bridges"""
|
||||
|
||||
import asyncio
|
||||
import inspect
|
||||
from typing import Any, Callable
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.python.failure import Failure
|
||||
|
||||
from libervia.backend.core.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
|
||||
|
||||
class QuickBridgeAdapter:
|
||||
"""Adapt legacy callback/errback to bridges
|
||||
|
||||
@param bridge: bridge instance
|
||||
"""
|
||||
|
||||
def __init__(self, bridge: Any) -> None:
|
||||
self._bridge = bridge
|
||||
|
||||
def __getattr__(self, name: str) -> Any:
|
||||
attr = getattr(self._bridge, name)
|
||||
if not callable(attr):
|
||||
return attr
|
||||
|
||||
def wrapper(*args: Any, **kwargs: Any) -> Any:
|
||||
callback = kwargs.pop("callback", None)
|
||||
errback = kwargs.pop("errback", None)
|
||||
result = attr(*args, **kwargs)
|
||||
if inspect.iscoroutine(result):
|
||||
result = asyncio.ensure_future(result)
|
||||
if isinstance(result, asyncio.Future):
|
||||
# async bridges (e.g. AIOBridge) return asyncio futures
|
||||
result = defer.Deferred.fromFuture(result)
|
||||
if (callback is None and errback is None) or not hasattr(
|
||||
result, "addCallback"
|
||||
):
|
||||
return result
|
||||
if callback is not None:
|
||||
result.addCallback(callback)
|
||||
if errback is not None:
|
||||
result.addErrback(errback)
|
||||
return result
|
||||
|
||||
return wrapper
|
||||
|
||||
def register_signal(self, name: str, handler: Callable, iface: str = "core") -> None:
|
||||
"""Register a signal handler, adapting sync handlers to async bridges
|
||||
|
||||
@param name: signal name
|
||||
@param handler: signal handler, sync or async
|
||||
@param iface: bridge interface ("core" or "plugin")
|
||||
"""
|
||||
if not inspect.iscoroutinefunction(handler):
|
||||
|
||||
async def async_handler(*args: Any,
|
||||
_handler: Callable = handler) -> None:
|
||||
_handler(*args)
|
||||
|
||||
handler = async_handler
|
||||
|
||||
try:
|
||||
self._bridge.register_signal(name, handler, iface)
|
||||
except AttributeError:
|
||||
log.warning(f"Signal {name} is not available on the bridge")
|
||||
|
||||
def bridge_connect(self, callback: Callable | None = None,
|
||||
errback: Callable | None = None) -> None:
|
||||
"""Connect to the bridge
|
||||
|
||||
@param callback: called when the bridge is connected
|
||||
@param errback: called with a twisted Failure on connection error
|
||||
"""
|
||||
|
||||
async def _connect() -> None:
|
||||
try:
|
||||
await self._bridge.bridge_connect()
|
||||
except Exception as e:
|
||||
if errback is not None:
|
||||
errback(Failure(e))
|
||||
else:
|
||||
if callback is not None:
|
||||
callback()
|
||||
|
||||
try:
|
||||
asyncio.get_running_loop()
|
||||
except RuntimeError:
|
||||
# the event loop is not running yet (frontends usually call connect_bridge()
|
||||
# before starting their loop)
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
except RuntimeError:
|
||||
loop = asyncio.new_event_loop()
|
||||
asyncio.set_event_loop(loop)
|
||||
loop.call_soon(asyncio.ensure_future, _connect())
|
||||
else:
|
||||
asyncio.ensure_future(_connect())
|
||||
|
|
@ -233,9 +233,16 @@ class QuickProfileManager(object):
|
|||
|
||||
def refill_profiles(self):
|
||||
"""Rebuild the list of profiles"""
|
||||
profiles = self.host.bridge.profiles_list_get()
|
||||
profiles.sort()
|
||||
self.set_profiles(profiles)
|
||||
self.host.bridge.profiles_list_get(
|
||||
callback=self._profiles_loaded,
|
||||
errback=self._profiles_list_eb,
|
||||
)
|
||||
|
||||
def _profiles_loaded(self, profiles):
|
||||
self.set_profiles(sorted(profiles))
|
||||
|
||||
def _profiles_list_eb(self, failure_):
|
||||
log.error("Can't get profiles list: {msg}".format(msg=failure_))
|
||||
|
||||
## Method which must be implemented by frontends ##
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue