comparison sat/plugins/plugin_adhoc_dbus.py @ 4037:524856bd7b19

massive refactoring to switch from camelCase to snake_case: historically, Libervia (SàT before) was using camelCase as allowed by PEP8 when using a pre-PEP8 code, to use the same coding style as in Twisted. However, snake_case is more readable and it's better to follow PEP8 best practices, so it has been decided to move on full snake_case. Because Libervia has a huge codebase, this ended with a ugly mix of camelCase and snake_case. To fix that, this patch does a big refactoring by renaming every function and method (including bridge) that are not coming from Twisted or Wokkel, to use fully snake_case. This is a massive change, and may result in some bugs.
author Goffi <goffi@goffi.org>
date Sat, 08 Apr 2023 13:54:42 +0200
parents 7550ae9cfbac
children
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
96 96
97 def __init__(self, host): 97 def __init__(self, host):
98 log.info(_("plugin Ad-Hoc D-Bus initialization")) 98 log.info(_("plugin Ad-Hoc D-Bus initialization"))
99 self.host = host 99 self.host = host
100 if etree is not None: 100 if etree is not None:
101 host.bridge.addMethod( 101 host.bridge.add_method(
102 "adHocDBusAddAuto", 102 "ad_hoc_dbus_add_auto",
103 ".plugin", 103 ".plugin",
104 in_sign="sasasasasasass", 104 in_sign="sasasasasasass",
105 out_sign="(sa(sss))", 105 out_sign="(sa(sss))",
106 method=self._adHocDBusAddAuto, 106 method=self._ad_hoc_dbus_add_auto,
107 async_=True, 107 async_=True,
108 ) 108 )
109 host.bridge.addMethod( 109 host.bridge.add_method(
110 "adHocRemotesGet", 110 "ad_hoc_remotes_get",
111 ".plugin", 111 ".plugin",
112 in_sign="s", 112 in_sign="s",
113 out_sign="a(sss)", 113 out_sign="a(sss)",
114 method=self._adHocRemotesGet, 114 method=self._ad_hoc_remotes_get,
115 async_=True, 115 async_=True,
116 ) 116 )
117 self._c = host.plugins["XEP-0050"] 117 self._c = host.plugins["XEP-0050"]
118 host.registerNamespace("mediaplayer", NS_MEDIA_PLAYER) 118 host.register_namespace("mediaplayer", NS_MEDIA_PLAYER)
119 if dbus is not None: 119 if dbus is not None:
120 self.session_bus = dbus.SessionBus() 120 self.session_bus = dbus.SessionBus()
121 self.fd_object = self.session_bus.get_object( 121 self.fd_object = self.session_bus.get_object(
122 FD_NAME, FD_PATH, introspect=False) 122 FD_NAME, FD_PATH, introspect=False)
123 123
124 def profileConnected(self, client): 124 def profile_connected(self, client):
125 if dbus is not None: 125 if dbus is not None:
126 self._c.addAdHocCommand( 126 self._c.add_ad_hoc_command(
127 client, self.localMediaCb, D_("Media Players"), 127 client, self.local_media_cb, D_("Media Players"),
128 node=NS_MEDIA_PLAYER, 128 node=NS_MEDIA_PLAYER,
129 timeout=60*60*6 # 6 hours timeout, to avoid breaking remote 129 timeout=60*60*6 # 6 hours timeout, to avoid breaking remote
130 # in the middle of a movie 130 # in the middle of a movie
131 ) 131 )
132 132
133 def _DBusAsyncCall(self, proxy, method, *args, **kwargs): 133 def _dbus_async_call(self, proxy, method, *args, **kwargs):
134 """ Call a DBus method asynchronously and return a deferred 134 """ Call a DBus method asynchronously and return a deferred
135 135
136 @param proxy: DBus object proxy, as returner by get_object 136 @param proxy: DBus object proxy, as returner by get_object
137 @param method: name of the method to call 137 @param method: name of the method to call
138 @param args: will be transmitted to the method 138 @param args: will be transmitted to the method
147 kwargs["reply_handler"] = lambda ret=None: d.callback(ret) 147 kwargs["reply_handler"] = lambda ret=None: d.callback(ret)
148 kwargs["error_handler"] = d.errback 148 kwargs["error_handler"] = d.errback
149 proxy.get_dbus_method(method, dbus_interface=interface)(*args, **kwargs) 149 proxy.get_dbus_method(method, dbus_interface=interface)(*args, **kwargs)
150 return d 150 return d
151 151
152 def _DBusGetProperty(self, proxy, interface, name): 152 def _dbus_get_property(self, proxy, interface, name):
153 return self._DBusAsyncCall( 153 return self._dbus_async_call(
154 proxy, "Get", interface, name, interface="org.freedesktop.DBus.Properties") 154 proxy, "Get", interface, name, interface="org.freedesktop.DBus.Properties")
155 155
156 156
157 def _DBusListNames(self): 157 def _dbus_list_names(self):
158 return self._DBusAsyncCall(self.fd_object, "ListNames") 158 return self._dbus_async_call(self.fd_object, "ListNames")
159 159
160 def _DBusIntrospect(self, proxy): 160 def _dbus_introspect(self, proxy):
161 return self._DBusAsyncCall(proxy, INTROSPECT_METHOD, interface=INTROSPECT_IFACE) 161 return self._dbus_async_call(proxy, INTROSPECT_METHOD, interface=INTROSPECT_IFACE)
162 162
163 def _acceptMethod(self, method): 163 def _accept_method(self, method):
164 """ Return True if we accept the method for a command 164 """ Return True if we accept the method for a command
165 @param method: etree.Element 165 @param method: etree.Element
166 @return: True if the method is acceptable 166 @return: True if the method is acceptable
167 167
168 """ 168 """
173 return True 173 return True
174 174
175 @defer.inlineCallbacks 175 @defer.inlineCallbacks
176 def _introspect(self, methods, bus_name, proxy): 176 def _introspect(self, methods, bus_name, proxy):
177 log.debug("introspecting path [%s]" % proxy.object_path) 177 log.debug("introspecting path [%s]" % proxy.object_path)
178 introspect_xml = yield self._DBusIntrospect(proxy) 178 introspect_xml = yield self._dbus_introspect(proxy)
179 el = etree.fromstring(introspect_xml) 179 el = etree.fromstring(introspect_xml)
180 for node in el.iterchildren("node", "interface"): 180 for node in el.iterchildren("node", "interface"):
181 if node.tag == "node": 181 if node.tag == "node":
182 new_path = os.path.join(proxy.object_path, node.get("name")) 182 new_path = os.path.join(proxy.object_path, node.get("name"))
183 new_proxy = self.session_bus.get_object( 183 new_proxy = self.session_bus.get_object(
189 if any(name.startswith(ignored) for ignored in IGNORED_IFACES_START): 189 if any(name.startswith(ignored) for ignored in IGNORED_IFACES_START):
190 log.debug("interface [%s] is ignored" % name) 190 log.debug("interface [%s] is ignored" % name)
191 continue 191 continue
192 log.debug("introspecting interface [%s]" % name) 192 log.debug("introspecting interface [%s]" % name)
193 for method in node.iterchildren("method"): 193 for method in node.iterchildren("method"):
194 if self._acceptMethod(method): 194 if self._accept_method(method):
195 method_name = method.get("name") 195 method_name = method.get("name")
196 log.debug("method accepted: [%s]" % method_name) 196 log.debug("method accepted: [%s]" % method_name)
197 methods.add((proxy.object_path, name, method_name)) 197 methods.add((proxy.object_path, name, method_name))
198 198
199 def _adHocDBusAddAuto(self, prog_name, allowed_jids, allowed_groups, allowed_magics, 199 def _ad_hoc_dbus_add_auto(self, prog_name, allowed_jids, allowed_groups, allowed_magics,
200 forbidden_jids, forbidden_groups, flags, profile_key): 200 forbidden_jids, forbidden_groups, flags, profile_key):
201 client = self.host.getClient(profile_key) 201 client = self.host.get_client(profile_key)
202 return self.adHocDBusAddAuto( 202 return self.ad_hoc_dbus_add_auto(
203 client, prog_name, allowed_jids, allowed_groups, allowed_magics, 203 client, prog_name, allowed_jids, allowed_groups, allowed_magics,
204 forbidden_jids, forbidden_groups, flags) 204 forbidden_jids, forbidden_groups, flags)
205 205
206 @defer.inlineCallbacks 206 @defer.inlineCallbacks
207 def adHocDBusAddAuto(self, client, prog_name, allowed_jids=None, allowed_groups=None, 207 def ad_hoc_dbus_add_auto(self, client, prog_name, allowed_jids=None, allowed_groups=None,
208 allowed_magics=None, forbidden_jids=None, forbidden_groups=None, 208 allowed_magics=None, forbidden_jids=None, forbidden_groups=None,
209 flags=None): 209 flags=None):
210 bus_names = yield self._DBusListNames() 210 bus_names = yield self._dbus_list_names()
211 bus_names = [bus_name for bus_name in bus_names if "." + prog_name in bus_name] 211 bus_names = [bus_name for bus_name in bus_names if "." + prog_name in bus_name]
212 if not bus_names: 212 if not bus_names:
213 log.info("Can't find any bus for [%s]" % prog_name) 213 log.info("Can't find any bus for [%s]" % prog_name)
214 defer.returnValue(("", [])) 214 defer.returnValue(("", []))
215 bus_names.sort() 215 bus_names.sort()
221 methods = set() 221 methods = set()
222 222
223 yield self._introspect(methods, bus_name, proxy) 223 yield self._introspect(methods, bus_name, proxy)
224 224
225 if methods: 225 if methods:
226 self._addCommand( 226 self._add_command(
227 client, 227 client,
228 prog_name, 228 prog_name,
229 bus_name, 229 bus_name,
230 methods, 230 methods,
231 allowed_jids=allowed_jids, 231 allowed_jids=allowed_jids,
236 flags=flags, 236 flags=flags,
237 ) 237 )
238 238
239 defer.returnValue((str(bus_name), methods)) 239 defer.returnValue((str(bus_name), methods))
240 240
241 def _addCommand(self, client, adhoc_name, bus_name, methods, allowed_jids=None, 241 def _add_command(self, client, adhoc_name, bus_name, methods, allowed_jids=None,
242 allowed_groups=None, allowed_magics=None, forbidden_jids=None, 242 allowed_groups=None, allowed_magics=None, forbidden_jids=None,
243 forbidden_groups=None, flags=None): 243 forbidden_groups=None, flags=None):
244 if flags is None: 244 if flags is None:
245 flags = set() 245 flags = set()
246 246
247 def DBusCallback(client, command_elt, session_data, action, node): 247 def d_bus_callback(client, command_elt, session_data, action, node):
248 actions = session_data.setdefault("actions", []) 248 actions = session_data.setdefault("actions", [])
249 names_map = session_data.setdefault("names_map", {}) 249 names_map = session_data.setdefault("names_map", {})
250 actions.append(action) 250 actions.append(action)
251 251
252 if len(actions) == 1: 252 if len(actions) == 1:
281 raise self._c.AdHocError(self._c.ERROR.BAD_PAYLOAD) 281 raise self._c.AdHocError(self._c.ERROR.BAD_PAYLOAD)
282 282
283 path, iface, command = names_map[command] 283 path, iface, command = names_map[command]
284 proxy = self.session_bus.get_object(bus_name, path) 284 proxy = self.session_bus.get_object(bus_name, path)
285 285
286 self._DBusAsyncCall(proxy, command, interface=iface) 286 self._dbus_async_call(proxy, command, interface=iface)
287 287
288 # job done, we can end the session, except if we have FLAG_LOOP 288 # job done, we can end the session, except if we have FLAG_LOOP
289 if FLAG_LOOP in flags: 289 if FLAG_LOOP in flags:
290 # We have a loop, so we clear everything and we execute again the 290 # We have a loop, so we clear everything and we execute again the
291 # command as we had a first call (command_elt is not used, so None 291 # command as we had a first call (command_elt is not used, so None
292 # is OK) 292 # is OK)
293 del actions[:] 293 del actions[:]
294 names_map.clear() 294 names_map.clear()
295 return DBusCallback( 295 return d_bus_callback(
296 client, None, session_data, self._c.ACTION.EXECUTE, node 296 client, None, session_data, self._c.ACTION.EXECUTE, node
297 ) 297 )
298 form = data_form.Form("form", title=_("Updated")) 298 form = data_form.Form("form", title=_("Updated"))
299 form.addField(data_form.Field("fixed", "Command sent")) 299 form.addField(data_form.Field("fixed", "Command sent"))
300 status = self._c.STATUS.COMPLETED 300 status = self._c.STATUS.COMPLETED
303 else: 303 else:
304 raise self._c.AdHocError(self._c.ERROR.INTERNAL) 304 raise self._c.AdHocError(self._c.ERROR.INTERNAL)
305 305
306 return (payload, status, None, note) 306 return (payload, status, None, note)
307 307
308 self._c.addAdHocCommand( 308 self._c.add_ad_hoc_command(
309 client, 309 client,
310 DBusCallback, 310 d_bus_callback,
311 adhoc_name, 311 adhoc_name,
312 allowed_jids=allowed_jids, 312 allowed_jids=allowed_jids,
313 allowed_groups=allowed_groups, 313 allowed_groups=allowed_groups,
314 allowed_magics=allowed_magics, 314 allowed_magics=allowed_magics,
315 forbidden_jids=forbidden_jids, 315 forbidden_jids=forbidden_jids,
316 forbidden_groups=forbidden_groups, 316 forbidden_groups=forbidden_groups,
317 ) 317 )
318 318
319 ## Local media ## 319 ## Local media ##
320 320
321 def _adHocRemotesGet(self, profile): 321 def _ad_hoc_remotes_get(self, profile):
322 return self.adHocRemotesGet(self.host.getClient(profile)) 322 return self.ad_hoc_remotes_get(self.host.get_client(profile))
323 323
324 @defer.inlineCallbacks 324 @defer.inlineCallbacks
325 def adHocRemotesGet(self, client): 325 def ad_hoc_remotes_get(self, client):
326 """Retrieve available remote media controlers in our devices 326 """Retrieve available remote media controlers in our devices
327 @return (list[tuple[unicode, unicode, unicode]]): list of devices with: 327 @return (list[tuple[unicode, unicode, unicode]]): list of devices with:
328 - entity full jid 328 - entity full jid
329 - device name 329 - device name
330 - device label 330 - device label
331 """ 331 """
332 found_data = yield defer.ensureDeferred(self.host.findByFeatures( 332 found_data = yield defer.ensureDeferred(self.host.find_by_features(
333 client, [self.host.ns_map['commands']], service=False, roster=False, 333 client, [self.host.ns_map['commands']], service=False, roster=False,
334 own_jid=True, local_device=True)) 334 own_jid=True, local_device=True))
335 335
336 remotes = [] 336 remotes = []
337 337
342 for cmd in cmd_list: 342 for cmd in cmd_list:
343 if cmd.nodeIdentifier == NS_MEDIA_PLAYER: 343 if cmd.nodeIdentifier == NS_MEDIA_PLAYER:
344 try: 344 try:
345 result_elt = yield self._c.do(client, device_jid, 345 result_elt = yield self._c.do(client, device_jid,
346 NS_MEDIA_PLAYER, timeout=5) 346 NS_MEDIA_PLAYER, timeout=5)
347 command_elt = self._c.getCommandElt(result_elt) 347 command_elt = self._c.get_command_elt(result_elt)
348 form = data_form.findForm(command_elt, NS_MEDIA_PLAYER) 348 form = data_form.findForm(command_elt, NS_MEDIA_PLAYER)
349 if form is None: 349 if form is None:
350 continue 350 continue
351 mp_options = form.fields['media_player'].options 351 mp_options = form.fields['media_player'].options
352 session_id = command_elt.getAttribute('sessionid') 352 session_id = command_elt.getAttribute('sessionid')
366 "Can't retrieve remote controllers on {device_jid}: " 366 "Can't retrieve remote controllers on {device_jid}: "
367 "{reason}".format(device_jid=device_jid, reason=e))) 367 "{reason}".format(device_jid=device_jid, reason=e)))
368 break 368 break
369 defer.returnValue(remotes) 369 defer.returnValue(remotes)
370 370
371 def doMPRISCommand(self, proxy, command): 371 def do_mpris_command(self, proxy, command):
372 iface, command = command.rsplit(".", 1) 372 iface, command = command.rsplit(".", 1)
373 if command == CMD_GO_BACK: 373 if command == CMD_GO_BACK:
374 command = 'Seek' 374 command = 'Seek'
375 args = [-SEEK_OFFSET] 375 args = [-SEEK_OFFSET]
376 elif command == CMD_GO_FWD: 376 elif command == CMD_GO_FWD:
377 command = 'Seek' 377 command = 'Seek'
378 args = [SEEK_OFFSET] 378 args = [SEEK_OFFSET]
379 else: 379 else:
380 args = [] 380 args = []
381 return self._DBusAsyncCall(proxy, command, *args, interface=iface) 381 return self._dbus_async_call(proxy, command, *args, interface=iface)
382 382
383 def addMPRISMetadata(self, form, metadata): 383 def add_mpris_metadata(self, form, metadata):
384 """Serialise MRPIS Metadata according to MPRIS_METADATA_MAP""" 384 """Serialise MRPIS Metadata according to MPRIS_METADATA_MAP"""
385 for mpris_key, name in MPRIS_METADATA_MAP.items(): 385 for mpris_key, name in MPRIS_METADATA_MAP.items():
386 if mpris_key in metadata: 386 if mpris_key in metadata:
387 value = str(metadata[mpris_key]) 387 value = str(metadata[mpris_key])
388 form.addField(data_form.Field(fieldType="fixed", 388 form.addField(data_form.Field(fieldType="fixed",
389 var=name, 389 var=name,
390 value=value)) 390 value=value))
391 391
392 @defer.inlineCallbacks 392 @defer.inlineCallbacks
393 def localMediaCb(self, client, command_elt, session_data, action, node): 393 def local_media_cb(self, client, command_elt, session_data, action, node):
394 try: 394 try:
395 x_elt = next(command_elt.elements(data_form.NS_X_DATA, "x")) 395 x_elt = next(command_elt.elements(data_form.NS_X_DATA, "x"))
396 command_form = data_form.Form.fromElement(x_elt) 396 command_form = data_form.Form.fromElement(x_elt)
397 except StopIteration: 397 except StopIteration:
398 command_form = None 398 command_form = None
399 399
400 if command_form is None or len(command_form.fields) == 0: 400 if command_form is None or len(command_form.fields) == 0:
401 # root request, we looks for media players 401 # root request, we looks for media players
402 bus_names = yield self._DBusListNames() 402 bus_names = yield self._dbus_list_names()
403 bus_names = [b for b in bus_names if b.startswith(MPRIS_PREFIX)] 403 bus_names = [b for b in bus_names if b.startswith(MPRIS_PREFIX)]
404 if len(bus_names) == 0: 404 if len(bus_names) == 0:
405 note = (self._c.NOTE.INFO, D_("No media player found.")) 405 note = (self._c.NOTE.INFO, D_("No media player found."))
406 defer.returnValue((None, self._c.STATUS.COMPLETED, None, note)) 406 defer.returnValue((None, self._c.STATUS.COMPLETED, None, note))
407 options = [] 407 options = []
443 try: 443 try:
444 command = command_form["command"] 444 command = command_form["command"]
445 except KeyError: 445 except KeyError:
446 pass 446 pass
447 else: 447 else:
448 yield self.doMPRISCommand(proxy, command) 448 yield self.do_mpris_command(proxy, command)
449 449
450 # we construct the remote control form 450 # we construct the remote control form
451 form = data_form.Form("form", title=D_("Media Player Selection")) 451 form = data_form.Form("form", title=D_("Media Player Selection"))
452 form.addField(data_form.Field(fieldType="hidden", 452 form.addField(data_form.Field(fieldType="hidden",
453 var="media_player", 453 var="media_player",
454 value=bus_name)) 454 value=bus_name))
455 for iface, properties_names in MPRIS_PROPERTIES.items(): 455 for iface, properties_names in MPRIS_PROPERTIES.items():
456 for name in properties_names: 456 for name in properties_names:
457 try: 457 try:
458 value = yield self._DBusGetProperty(proxy, iface, name) 458 value = yield self._dbus_get_property(proxy, iface, name)
459 except Exception as e: 459 except Exception as e:
460 log.warning(_("Can't retrieve attribute {name}: {reason}") 460 log.warning(_("Can't retrieve attribute {name}: {reason}")
461 .format(name=name, reason=e)) 461 .format(name=name, reason=e))
462 continue 462 continue
463 if name == MPRIS_METADATA_KEY: 463 if name == MPRIS_METADATA_KEY:
464 self.addMPRISMetadata(form, value) 464 self.add_mpris_metadata(form, value)
465 else: 465 else:
466 form.addField(data_form.Field(fieldType="fixed", 466 form.addField(data_form.Field(fieldType="fixed",
467 var=name, 467 var=name,
468 value=str(value))) 468 value=str(value)))
469 469