plugin ad-hoc D-Bus: fix deprecated use of python-dbus:
the plugin was using python-dbus which is deprecated in the backend in the favor of TxDBus. Methods calls have been updated, and the plugin works again, but there seems to be still some issues (warnings in the logs). Those will be fixed later.
This commit is contained in:
parent
3c35dea8b1
commit
ec2a637847
2 changed files with 79 additions and 75 deletions
|
|
@ -17,14 +17,21 @@
|
|||
# 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.core.i18n import D_, _
|
||||
from collections import OrderedDict
|
||||
import os.path
|
||||
import uuid
|
||||
|
||||
from twisted.internet import defer
|
||||
from twisted.internet import reactor
|
||||
from twisted.words.protocols.jabber import jid
|
||||
from wokkel import data_form
|
||||
|
||||
from libervia.backend.core.constants import Const as C
|
||||
from libervia.backend.core.i18n import D_, _
|
||||
from libervia.backend.core.log import getLogger
|
||||
|
||||
log = getLogger(__name__)
|
||||
from twisted.internet import defer
|
||||
from twisted.words.protocols.jabber import jid
|
||||
from wokkel import data_form
|
||||
|
||||
|
||||
try:
|
||||
from lxml import etree
|
||||
|
|
@ -32,19 +39,17 @@ except ImportError:
|
|||
etree = None
|
||||
log.warning("Missing module lxml, please download/install it from http://lxml.de/ ."
|
||||
"Auto D-Bus discovery will be disabled")
|
||||
from collections import OrderedDict
|
||||
import os.path
|
||||
import uuid
|
||||
try:
|
||||
import dbus
|
||||
from dbus.mainloop.glib import DBusGMainLoop
|
||||
except ImportError:
|
||||
dbus = None
|
||||
log.warning("Missing module dbus, please download/install it, "
|
||||
"auto D-Bus discovery will be disabled")
|
||||
|
||||
else:
|
||||
DBusGMainLoop(set_as_default=True)
|
||||
try:
|
||||
import txdbus
|
||||
from txdbus import client as dbus_client
|
||||
except ImportError:
|
||||
txdbus = None
|
||||
log.warning(
|
||||
"Missing module txdbus, please download/install it, auto D-Bus discovery will be "
|
||||
"disabled"
|
||||
)
|
||||
|
||||
|
||||
NS_MEDIA_PLAYER = "org.libervia.mediaplayer"
|
||||
FD_NAME = "org.freedesktop.DBus"
|
||||
|
|
@ -92,10 +97,10 @@ PLUGIN_INFO = {
|
|||
}
|
||||
|
||||
|
||||
class AdHocDBus(object):
|
||||
class AdHocDBus:
|
||||
|
||||
def __init__(self, host):
|
||||
log.info(_("plugin Ad-Hoc D-Bus initialization"))
|
||||
log.info(f"plugin {PLUGIN_INFO[C.PI_NAME]!r} initialization")
|
||||
self.host = host
|
||||
if etree is not None:
|
||||
host.bridge.add_method(
|
||||
|
|
@ -116,13 +121,14 @@ class AdHocDBus(object):
|
|||
)
|
||||
self._c = host.plugins["XEP-0050"]
|
||||
host.register_namespace("mediaplayer", NS_MEDIA_PLAYER)
|
||||
if dbus is not None:
|
||||
self.session_bus = dbus.SessionBus()
|
||||
self.fd_object = self.session_bus.get_object(
|
||||
FD_NAME, FD_PATH, introspect=False)
|
||||
self.session_con = None
|
||||
|
||||
async def profile_connected(self, client):
|
||||
if txdbus is not None:
|
||||
if self.session_con is None:
|
||||
self.session_con = await dbus_client.connect(reactor, 'session')
|
||||
self.fd_object = await self.session_con.getRemoteObject(FD_NAME, FD_PATH)
|
||||
|
||||
def profile_connected(self, client):
|
||||
if dbus is not None:
|
||||
self._c.add_ad_hoc_command(
|
||||
client, self.local_media_cb, D_("Media Players"),
|
||||
node=NS_MEDIA_PLAYER,
|
||||
|
|
@ -130,7 +136,7 @@ class AdHocDBus(object):
|
|||
# in the middle of a movie
|
||||
)
|
||||
|
||||
def _dbus_async_call(self, proxy, method, *args, **kwargs):
|
||||
async def _dbus_async_call(self, proxy, method, *args, **kwargs):
|
||||
""" Call a DBus method asynchronously and return a deferred
|
||||
|
||||
@param proxy: DBus object proxy, as returner by get_object
|
||||
|
|
@ -142,23 +148,18 @@ class AdHocDBus(object):
|
|||
@return: a deferred
|
||||
|
||||
"""
|
||||
d = defer.Deferred()
|
||||
interface = kwargs.pop("interface", None)
|
||||
kwargs["reply_handler"] = lambda ret=None: d.callback(ret)
|
||||
kwargs["error_handler"] = d.errback
|
||||
proxy.get_dbus_method(method, dbus_interface=interface)(*args, **kwargs)
|
||||
return d
|
||||
return await proxy.callRemote(method, *args, **kwargs)
|
||||
|
||||
def _dbus_get_property(self, proxy, interface, name):
|
||||
return self._dbus_async_call(
|
||||
async def _dbus_get_property(self, proxy, interface, name):
|
||||
return await self._dbus_async_call(
|
||||
proxy, "Get", interface, name, interface="org.freedesktop.DBus.Properties")
|
||||
|
||||
|
||||
def _dbus_list_names(self):
|
||||
return self._dbus_async_call(self.fd_object, "ListNames")
|
||||
async def _dbus_list_names(self):
|
||||
return await self.fd_object.callRemote("ListNames")
|
||||
|
||||
def _dbus_introspect(self, proxy):
|
||||
return self._dbus_async_call(proxy, INTROSPECT_METHOD, interface=INTROSPECT_IFACE)
|
||||
async def _dbus_introspect(self, proxy):
|
||||
return await self._dbus_async_call(proxy, INTROSPECT_METHOD, interface=INTROSPECT_IFACE)
|
||||
|
||||
def _accept_method(self, method):
|
||||
""" Return True if we accept the method for a command
|
||||
|
|
@ -172,18 +173,18 @@ class AdHocDBus(object):
|
|||
return False
|
||||
return True
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def _introspect(self, methods, bus_name, proxy):
|
||||
async def _introspect(self, methods, bus_name, proxy):
|
||||
log.debug("introspecting path [%s]" % proxy.object_path)
|
||||
introspect_xml = yield self._dbus_introspect(proxy)
|
||||
assert etree is not None
|
||||
introspect_xml = await self._dbus_introspect(proxy)
|
||||
el = etree.fromstring(introspect_xml)
|
||||
for node in el.iterchildren("node", "interface"):
|
||||
if node.tag == "node":
|
||||
new_path = os.path.join(proxy.object_path, node.get("name"))
|
||||
new_proxy = self.session_bus.get_object(
|
||||
bus_name, new_path, introspect=False
|
||||
new_proxy = await self.session_con.getRemoteObject(
|
||||
bus_name, new_path
|
||||
)
|
||||
yield self._introspect(methods, bus_name, new_proxy)
|
||||
await self._introspect(methods, bus_name, new_proxy)
|
||||
elif node.tag == "interface":
|
||||
name = node.get("name")
|
||||
if any(name.startswith(ignored) for ignored in IGNORED_IFACES_START):
|
||||
|
|
@ -203,24 +204,26 @@ class AdHocDBus(object):
|
|||
client, prog_name, allowed_jids, allowed_groups, allowed_magics,
|
||||
forbidden_jids, forbidden_groups, flags)
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def ad_hoc_dbus_add_auto(self, client, prog_name, allowed_jids=None, allowed_groups=None,
|
||||
async def ad_hoc_dbus_add_auto(self, client, prog_name, allowed_jids=None, allowed_groups=None,
|
||||
allowed_magics=None, forbidden_jids=None, forbidden_groups=None,
|
||||
flags=None):
|
||||
bus_names = yield self._dbus_list_names()
|
||||
bus_names = await self._dbus_list_names()
|
||||
bus_names = [bus_name for bus_name in bus_names if "." + prog_name in bus_name]
|
||||
if not bus_names:
|
||||
log.info("Can't find any bus for [%s]" % prog_name)
|
||||
defer.returnValue(("", []))
|
||||
return ("", [])
|
||||
bus_names.sort()
|
||||
for bus_name in bus_names:
|
||||
if bus_name.endswith(prog_name):
|
||||
break
|
||||
log.info("bus name found: [%s]" % bus_name)
|
||||
proxy = self.session_bus.get_object(bus_name, "/", introspect=False)
|
||||
else:
|
||||
log.info(f"Can't find any command for {prog_name}")
|
||||
return ("", [])
|
||||
log.info(f"bus name found: {bus_name}")
|
||||
proxy = await self.session_con.getRemoteObject(bus_name, "/")
|
||||
methods = set()
|
||||
|
||||
yield self._introspect(methods, bus_name, proxy)
|
||||
await self._introspect(methods, bus_name, proxy)
|
||||
|
||||
if methods:
|
||||
self._add_command(
|
||||
|
|
@ -236,7 +239,7 @@ class AdHocDBus(object):
|
|||
flags=flags,
|
||||
)
|
||||
|
||||
defer.returnValue((str(bus_name), methods))
|
||||
return (str(bus_name), methods)
|
||||
|
||||
def _add_command(self, client, adhoc_name, bus_name, methods, allowed_jids=None,
|
||||
allowed_groups=None, allowed_magics=None, forbidden_jids=None,
|
||||
|
|
@ -244,7 +247,7 @@ class AdHocDBus(object):
|
|||
if flags is None:
|
||||
flags = set()
|
||||
|
||||
def d_bus_callback(client, command_elt, session_data, action, node):
|
||||
async def d_bus_callback(client, command_elt, session_data, action, node):
|
||||
actions = session_data.setdefault("actions", [])
|
||||
names_map = session_data.setdefault("names_map", {})
|
||||
actions.append(action)
|
||||
|
|
@ -281,9 +284,9 @@ class AdHocDBus(object):
|
|||
raise self._c.AdHocError(self._c.ERROR.BAD_PAYLOAD)
|
||||
|
||||
path, iface, command = names_map[command]
|
||||
proxy = self.session_bus.get_object(bus_name, path)
|
||||
proxy = await self.session_con.getRemoteObject(bus_name, path)
|
||||
|
||||
self._dbus_async_call(proxy, command, interface=iface)
|
||||
await self._dbus_async_call(proxy, command, interface=iface)
|
||||
|
||||
# job done, we can end the session, except if we have FLAG_LOOP
|
||||
if FLAG_LOOP in flags:
|
||||
|
|
@ -292,7 +295,7 @@ class AdHocDBus(object):
|
|||
# is OK)
|
||||
del actions[:]
|
||||
names_map.clear()
|
||||
return d_bus_callback(
|
||||
return await d_bus_callback(
|
||||
client, None, session_data, self._c.ACTION.EXECUTE, node
|
||||
)
|
||||
form = data_form.Form("form", title=_("Updated"))
|
||||
|
|
@ -321,15 +324,14 @@ class AdHocDBus(object):
|
|||
def _ad_hoc_remotes_get(self, profile):
|
||||
return self.ad_hoc_remotes_get(self.host.get_client(profile))
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def ad_hoc_remotes_get(self, client):
|
||||
async def ad_hoc_remotes_get(self, client):
|
||||
"""Retrieve available remote media controlers in our devices
|
||||
@return (list[tuple[unicode, unicode, unicode]]): list of devices with:
|
||||
- entity full jid
|
||||
- device name
|
||||
- device label
|
||||
"""
|
||||
found_data = yield defer.ensureDeferred(self.host.find_by_features(
|
||||
found_data = await defer.ensureDeferred(self.host.find_by_features(
|
||||
client, [self.host.ns_map['commands']], service=False, roster=False,
|
||||
own_jid=True, local_device=True))
|
||||
|
||||
|
|
@ -338,11 +340,11 @@ class AdHocDBus(object):
|
|||
for found in found_data:
|
||||
for device_jid_s in found:
|
||||
device_jid = jid.JID(device_jid_s)
|
||||
cmd_list = yield self._c.list(client, device_jid)
|
||||
cmd_list = await self._c.list(client, device_jid)
|
||||
for cmd in cmd_list:
|
||||
if cmd.nodeIdentifier == NS_MEDIA_PLAYER:
|
||||
try:
|
||||
result_elt = yield self._c.do(client, device_jid,
|
||||
result_elt = await self._c.do(client, device_jid,
|
||||
NS_MEDIA_PLAYER, timeout=5)
|
||||
command_elt = self._c.get_command_elt(result_elt)
|
||||
form = data_form.findForm(command_elt, NS_MEDIA_PLAYER)
|
||||
|
|
@ -366,9 +368,9 @@ class AdHocDBus(object):
|
|||
"Can't retrieve remote controllers on {device_jid}: "
|
||||
"{reason}".format(device_jid=device_jid, reason=e)))
|
||||
break
|
||||
defer.returnValue(remotes)
|
||||
return remotes
|
||||
|
||||
def do_mpris_command(self, proxy, command):
|
||||
async def do_mpris_command(self, proxy, command):
|
||||
iface, command = command.rsplit(".", 1)
|
||||
if command == CMD_GO_BACK:
|
||||
command = 'Seek'
|
||||
|
|
@ -378,7 +380,7 @@ class AdHocDBus(object):
|
|||
args = [SEEK_OFFSET]
|
||||
else:
|
||||
args = []
|
||||
return self._dbus_async_call(proxy, command, *args, interface=iface)
|
||||
return await self._dbus_async_call(proxy, command, *args, interface=iface)
|
||||
|
||||
def add_mpris_metadata(self, form, metadata):
|
||||
"""Serialise MRPIS Metadata according to MPRIS_METADATA_MAP"""
|
||||
|
|
@ -389,8 +391,8 @@ class AdHocDBus(object):
|
|||
var=name,
|
||||
value=value))
|
||||
|
||||
@defer.inlineCallbacks
|
||||
def local_media_cb(self, client, command_elt, session_data, action, node):
|
||||
async def local_media_cb(self, client, command_elt, session_data, action, node):
|
||||
assert txdbus is not None
|
||||
try:
|
||||
x_elt = next(command_elt.elements(data_form.NS_X_DATA, "x"))
|
||||
command_form = data_form.Form.fromElement(x_elt)
|
||||
|
|
@ -399,11 +401,11 @@ class AdHocDBus(object):
|
|||
|
||||
if command_form is None or len(command_form.fields) == 0:
|
||||
# root request, we looks for media players
|
||||
bus_names = yield self._dbus_list_names()
|
||||
bus_names = await self._dbus_list_names()
|
||||
bus_names = [b for b in bus_names if b.startswith(MPRIS_PREFIX)]
|
||||
if len(bus_names) == 0:
|
||||
note = (self._c.NOTE.INFO, D_("No media player found."))
|
||||
defer.returnValue((None, self._c.STATUS.COMPLETED, None, note))
|
||||
return (None, self._c.STATUS.COMPLETED, None, note)
|
||||
options = []
|
||||
status = self._c.STATUS.EXECUTING
|
||||
form = data_form.Form("form", title=D_("Media Player Selection"),
|
||||
|
|
@ -419,7 +421,7 @@ class AdHocDBus(object):
|
|||
)
|
||||
form.addField(field)
|
||||
payload = form.toElement()
|
||||
defer.returnValue((payload, status, None, None))
|
||||
return (payload, status, None, None)
|
||||
else:
|
||||
# player request
|
||||
try:
|
||||
|
|
@ -432,20 +434,22 @@ class AdHocDBus(object):
|
|||
"Hack attempt? Refused bus: {bus_name}").format(
|
||||
bus_name=bus_name))
|
||||
note = (self._c.NOTE.ERROR, D_("Invalid player name."))
|
||||
defer.returnValue((None, self._c.STATUS.COMPLETED, None, note))
|
||||
return (None, self._c.STATUS.COMPLETED, None, note)
|
||||
|
||||
try:
|
||||
proxy = self.session_bus.get_object(bus_name, MPRIS_PATH)
|
||||
except dbus.exceptions.DBusException as e:
|
||||
proxy = await self.session_con.getRemoteObject(
|
||||
bus_name, MPRIS_PATH, "org.mpris.MediaPlayer2.Player"
|
||||
)
|
||||
except Exception as e:
|
||||
log.warning(_("Can't get D-Bus proxy: {reason}").format(reason=e))
|
||||
note = (self._c.NOTE.ERROR, D_("Media player is not available anymore"))
|
||||
defer.returnValue((None, self._c.STATUS.COMPLETED, None, note))
|
||||
return (None, self._c.STATUS.COMPLETED, None, note)
|
||||
try:
|
||||
command = command_form["command"]
|
||||
except KeyError:
|
||||
pass
|
||||
else:
|
||||
yield self.do_mpris_command(proxy, command)
|
||||
await self.do_mpris_command(proxy, command)
|
||||
|
||||
# we construct the remote control form
|
||||
form = data_form.Form("form", title=D_("Media Player Selection"))
|
||||
|
|
@ -455,7 +459,7 @@ class AdHocDBus(object):
|
|||
for iface, properties_names in MPRIS_PROPERTIES.items():
|
||||
for name in properties_names:
|
||||
try:
|
||||
value = yield self._dbus_get_property(proxy, iface, name)
|
||||
value = await self._dbus_get_property(proxy, iface, name)
|
||||
except Exception as e:
|
||||
log.warning(_("Can't retrieve attribute {name}: {reason}")
|
||||
.format(name=name, reason=e))
|
||||
|
|
@ -475,4 +479,4 @@ class AdHocDBus(object):
|
|||
|
||||
payload = form.toElement()
|
||||
status = self._c.STATUS.EXECUTING
|
||||
defer.returnValue((payload, status, None, None))
|
||||
return (payload, status, None, None)
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ class Run(base.CommandBase):
|
|||
"-j",
|
||||
"--jid",
|
||||
default="",
|
||||
help=_("jid of the service (default: profile's server"),
|
||||
help=_("jid of the service (default: profile's server)"),
|
||||
)
|
||||
self.parser.add_argument(
|
||||
"-S",
|
||||
|
|
|
|||
Loading…
Reference in a new issue