comparison sat/plugins/plugin_adhoc_dbus.py @ 2624:56f94936df1e

code style reformatting using black
author Goffi <goffi@goffi.org>
date Wed, 27 Jun 2018 20:14:46 +0200
parents 26edcf3a30eb
children 8dd9db785ac8
comparison
equal deleted inserted replaced
2623:49533de4540b 2624:56f94936df1e
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. 18 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 19
20 from sat.core.i18n import _ 20 from sat.core.i18n import _
21 from sat.core.constants import Const as C 21 from sat.core.constants import Const as C
22 from sat.core.log import getLogger 22 from sat.core.log import getLogger
23
23 log = getLogger(__name__) 24 log = getLogger(__name__)
24 from sat.core import exceptions 25 from sat.core import exceptions
25 from twisted.internet import defer 26 from twisted.internet import defer
26 from wokkel import data_form 27 from wokkel import data_form
28
27 try: 29 try:
28 from lxml import etree 30 from lxml import etree
29 except ImportError: 31 except ImportError:
30 raise exceptions.MissingModule(u"Missing module lxml, please download/install it from http://lxml.de/") 32 raise exceptions.MissingModule(
33 u"Missing module lxml, please download/install it from http://lxml.de/"
34 )
31 import os.path 35 import os.path
32 import uuid 36 import uuid
33 import dbus 37 import dbus
34 from dbus.mainloop.glib import DBusGMainLoop 38 from dbus.mainloop.glib import DBusGMainLoop
39
35 DBusGMainLoop(set_as_default=True) 40 DBusGMainLoop(set_as_default=True)
36 41
37 FD_NAME = "org.freedesktop.DBus" 42 FD_NAME = "org.freedesktop.DBus"
38 FD_PATH = "/org/freedekstop/DBus" 43 FD_PATH = "/org/freedekstop/DBus"
39 INTROSPECT_IFACE = "org.freedesktop.DBus.Introspectable" 44 INTROSPECT_IFACE = "org.freedesktop.DBus.Introspectable"
40 45
41 INTROSPECT_METHOD = "Introspect" 46 INTROSPECT_METHOD = "Introspect"
42 IGNORED_IFACES_START = ('org.freedesktop', 'org.qtproject', 'org.kde.KMainWindow') # commands in interface starting with these values will be ignored 47 IGNORED_IFACES_START = (
43 FLAG_LOOP = 'LOOP' 48 "org.freedesktop",
49 "org.qtproject",
50 "org.kde.KMainWindow",
51 ) # commands in interface starting with these values will be ignored
52 FLAG_LOOP = "LOOP"
44 53
45 PLUGIN_INFO = { 54 PLUGIN_INFO = {
46 C.PI_NAME: "Ad-Hoc Commands - D-Bus", 55 C.PI_NAME: "Ad-Hoc Commands - D-Bus",
47 C.PI_IMPORT_NAME: "AD_HOC_DBUS", 56 C.PI_IMPORT_NAME: "AD_HOC_DBUS",
48 C.PI_TYPE: "Misc", 57 C.PI_TYPE: "Misc",
49 C.PI_PROTOCOLS: [], 58 C.PI_PROTOCOLS: [],
50 C.PI_DEPENDENCIES: ["XEP-0050"], 59 C.PI_DEPENDENCIES: ["XEP-0050"],
51 C.PI_MAIN: "AdHocDBus", 60 C.PI_MAIN: "AdHocDBus",
52 C.PI_HANDLER: "no", 61 C.PI_HANDLER: "no",
53 C.PI_DESCRIPTION: _("""Add D-Bus management to Ad-Hoc commands""") 62 C.PI_DESCRIPTION: _("""Add D-Bus management to Ad-Hoc commands"""),
54 } 63 }
55 64
56 65
57 class AdHocDBus(object): 66 class AdHocDBus(object):
58
59 def __init__(self, host): 67 def __init__(self, host):
60 log.info(_("plugin Ad-Hoc D-Bus initialization")) 68 log.info(_("plugin Ad-Hoc D-Bus initialization"))
61 self.host = host 69 self.host = host
62 host.bridge.addMethod("adHocDBusAddAuto", ".plugin", in_sign='sasasasasasass', out_sign='(sa(sss))', 70 host.bridge.addMethod(
63 method=self._adHocDBusAddAuto, 71 "adHocDBusAddAuto",
64 async=True) 72 ".plugin",
73 in_sign="sasasasasasass",
74 out_sign="(sa(sss))",
75 method=self._adHocDBusAddAuto,
76 async=True,
77 )
65 self.session_bus = dbus.SessionBus() 78 self.session_bus = dbus.SessionBus()
66 self.fd_object = self.session_bus.get_object(FD_NAME, FD_PATH, introspect=False) 79 self.fd_object = self.session_bus.get_object(FD_NAME, FD_PATH, introspect=False)
67 self.XEP_0050 = host.plugins['XEP-0050'] 80 self.XEP_0050 = host.plugins["XEP-0050"]
68 81
69 def _DBusAsyncCall(self, proxy, method, *args, **kwargs): 82 def _DBusAsyncCall(self, proxy, method, *args, **kwargs):
70 """ Call a DBus method asynchronously and return a deferred 83 """ Call a DBus method asynchronously and return a deferred
71 @param proxy: DBus object proxy, as returner by get_object 84 @param proxy: DBus object proxy, as returner by get_object
72 @param method: name of the method to call 85 @param method: name of the method to call
75 - interface: name of the interface to use 88 - interface: name of the interface to use
76 @return: a deferred 89 @return: a deferred
77 90
78 """ 91 """
79 d = defer.Deferred() 92 d = defer.Deferred()
80 interface = kwargs.pop('interface', None) 93 interface = kwargs.pop("interface", None)
81 kwargs['reply_handler'] = lambda ret=None: d.callback(ret) 94 kwargs["reply_handler"] = lambda ret=None: d.callback(ret)
82 kwargs['error_handler'] = d.errback 95 kwargs["error_handler"] = d.errback
83 proxy.get_dbus_method(method, dbus_interface=interface)(*args, **kwargs) 96 proxy.get_dbus_method(method, dbus_interface=interface)(*args, **kwargs)
84 return d 97 return d
85 98
86 def _DBusListNames(self): 99 def _DBusListNames(self):
87 return self._DBusAsyncCall(self.fd_object, "ListNames") 100 return self._DBusAsyncCall(self.fd_object, "ListNames")
93 """ Return True if we accept the method for a command 106 """ Return True if we accept the method for a command
94 @param method: etree.Element 107 @param method: etree.Element
95 @return: True if the method is acceptable 108 @return: True if the method is acceptable
96 109
97 """ 110 """
98 if method.xpath("arg[@direction='in']"): # we don't accept method with argument for the moment 111 if method.xpath(
112 "arg[@direction='in']"
113 ): # we don't accept method with argument for the moment
99 return False 114 return False
100 return True 115 return True
101 116
102 @defer.inlineCallbacks 117 @defer.inlineCallbacks
103 def _introspect(self, methods, bus_name, proxy): 118 def _introspect(self, methods, bus_name, proxy):
104 log.debug("introspecting path [%s]" % proxy.object_path) 119 log.debug("introspecting path [%s]" % proxy.object_path)
105 introspect_xml = yield self._DBusIntrospect(proxy) 120 introspect_xml = yield self._DBusIntrospect(proxy)
106 el = etree.fromstring(introspect_xml) 121 el = etree.fromstring(introspect_xml)
107 for node in el.iterchildren('node', 'interface'): 122 for node in el.iterchildren("node", "interface"):
108 if node.tag == 'node': 123 if node.tag == "node":
109 new_path = os.path.join(proxy.object_path, node.get('name')) 124 new_path = os.path.join(proxy.object_path, node.get("name"))
110 new_proxy = self.session_bus.get_object(bus_name, new_path, introspect=False) 125 new_proxy = self.session_bus.get_object(
126 bus_name, new_path, introspect=False
127 )
111 yield self._introspect(methods, bus_name, new_proxy) 128 yield self._introspect(methods, bus_name, new_proxy)
112 elif node.tag == 'interface': 129 elif node.tag == "interface":
113 name = node.get('name') 130 name = node.get("name")
114 if any(name.startswith(ignored) for ignored in IGNORED_IFACES_START): 131 if any(name.startswith(ignored) for ignored in IGNORED_IFACES_START):
115 log.debug('interface [%s] is ignored' % name) 132 log.debug("interface [%s] is ignored" % name)
116 continue 133 continue
117 log.debug("introspecting interface [%s]" % name) 134 log.debug("introspecting interface [%s]" % name)
118 for method in node.iterchildren('method'): 135 for method in node.iterchildren("method"):
119 if self._acceptMethod(method): 136 if self._acceptMethod(method):
120 method_name = method.get('name') 137 method_name = method.get("name")
121 log.debug("method accepted: [%s]" % method_name) 138 log.debug("method accepted: [%s]" % method_name)
122 methods.add((proxy.object_path, name, method_name)) 139 methods.add((proxy.object_path, name, method_name))
123 140
124 def _adHocDBusAddAuto(self, prog_name, allowed_jids, allowed_groups, allowed_magics, forbidden_jids, forbidden_groups, flags, profile_key): 141 def _adHocDBusAddAuto(
125 return self.adHocDBusAddAuto(prog_name, allowed_jids, allowed_groups, allowed_magics, forbidden_jids, forbidden_groups, flags, profile_key) 142 self,
143 prog_name,
144 allowed_jids,
145 allowed_groups,
146 allowed_magics,
147 forbidden_jids,
148 forbidden_groups,
149 flags,
150 profile_key,
151 ):
152 return self.adHocDBusAddAuto(
153 prog_name,
154 allowed_jids,
155 allowed_groups,
156 allowed_magics,
157 forbidden_jids,
158 forbidden_groups,
159 flags,
160 profile_key,
161 )
126 162
127 @defer.inlineCallbacks 163 @defer.inlineCallbacks
128 def adHocDBusAddAuto(self, prog_name, allowed_jids=None, allowed_groups=None, allowed_magics=None, forbidden_jids=None, forbidden_groups=None, flags=None, profile_key=C.PROF_KEY_NONE): 164 def adHocDBusAddAuto(
165 self,
166 prog_name,
167 allowed_jids=None,
168 allowed_groups=None,
169 allowed_magics=None,
170 forbidden_jids=None,
171 forbidden_groups=None,
172 flags=None,
173 profile_key=C.PROF_KEY_NONE,
174 ):
129 bus_names = yield self._DBusListNames() 175 bus_names = yield self._DBusListNames()
130 bus_names = [bus_name for bus_name in bus_names if '.' + prog_name in bus_name] 176 bus_names = [bus_name for bus_name in bus_names if "." + prog_name in bus_name]
131 if not bus_names: 177 if not bus_names:
132 log.info("Can't find any bus for [%s]" % prog_name) 178 log.info("Can't find any bus for [%s]" % prog_name)
133 defer.returnValue(("", [])) 179 defer.returnValue(("", []))
134 bus_names.sort() 180 bus_names.sort()
135 for bus_name in bus_names: 181 for bus_name in bus_names:
136 if bus_name.endswith(prog_name): 182 if bus_name.endswith(prog_name):
137 break 183 break
138 log.info("bus name found: [%s]" % bus_name) 184 log.info("bus name found: [%s]" % bus_name)
139 proxy = self.session_bus.get_object(bus_name, '/', introspect=False) 185 proxy = self.session_bus.get_object(bus_name, "/", introspect=False)
140 methods = set() 186 methods = set()
141 187
142 yield self._introspect(methods, bus_name, proxy) 188 yield self._introspect(methods, bus_name, proxy)
143 189
144 if methods: 190 if methods:
145 self._addCommand(prog_name, bus_name, methods, 191 self._addCommand(
146 allowed_jids = allowed_jids, 192 prog_name,
147 allowed_groups = allowed_groups, 193 bus_name,
148 allowed_magics = allowed_magics, 194 methods,
149 forbidden_jids = forbidden_jids, 195 allowed_jids=allowed_jids,
150 forbidden_groups = forbidden_groups, 196 allowed_groups=allowed_groups,
151 flags = flags, 197 allowed_magics=allowed_magics,
152 profile_key = profile_key) 198 forbidden_jids=forbidden_jids,
199 forbidden_groups=forbidden_groups,
200 flags=flags,
201 profile_key=profile_key,
202 )
153 203
154 defer.returnValue((bus_name, methods)) 204 defer.returnValue((bus_name, methods))
155 205
156 206 def _addCommand(
157 def _addCommand(self, adhoc_name, bus_name, methods, allowed_jids=None, allowed_groups=None, allowed_magics=None, forbidden_jids=None, forbidden_groups=None, flags=None, profile_key=C.PROF_KEY_NONE): 207 self,
208 adhoc_name,
209 bus_name,
210 methods,
211 allowed_jids=None,
212 allowed_groups=None,
213 allowed_magics=None,
214 forbidden_jids=None,
215 forbidden_groups=None,
216 flags=None,
217 profile_key=C.PROF_KEY_NONE,
218 ):
158 if flags is None: 219 if flags is None:
159 flags = set() 220 flags = set()
160 221
161 def DBusCallback(command_elt, session_data, action, node, profile): 222 def DBusCallback(command_elt, session_data, action, node, profile):
162 actions = session_data.setdefault('actions',[]) 223 actions = session_data.setdefault("actions", [])
163 names_map = session_data.setdefault('names_map', {}) 224 names_map = session_data.setdefault("names_map", {})
164 actions.append(action) 225 actions.append(action)
165 226
166 if len(actions) == 1: 227 if len(actions) == 1:
167 # it's our first request, we ask the desired new status 228 # it's our first request, we ask the desired new status
168 status = self.XEP_0050.STATUS.EXECUTING 229 status = self.XEP_0050.STATUS.EXECUTING
169 form = data_form.Form('form', title=_('Command selection')) 230 form = data_form.Form("form", title=_("Command selection"))
170 options = [] 231 options = []
171 for path, iface, command in methods: 232 for path, iface, command in methods:
172 label = command.rsplit('.',1)[-1] 233 label = command.rsplit(".", 1)[-1]
173 name = str(uuid.uuid4()) 234 name = str(uuid.uuid4())
174 names_map[name] = (path, iface, command) 235 names_map[name] = (path, iface, command)
175 options.append(data_form.Option(name, label)) 236 options.append(data_form.Option(name, label))
176 237
177 field = data_form.Field('list-single', 'command', options=options, required=True) 238 field = data_form.Field(
239 "list-single", "command", options=options, required=True
240 )
178 form.addField(field) 241 form.addField(field)
179 242
180 payload = form.toElement() 243 payload = form.toElement()
181 note = None 244 note = None
182 245
183 elif len(actions) == 2: 246 elif len(actions) == 2:
184 # we should have the answer here 247 # we should have the answer here
185 try: 248 try:
186 x_elt = command_elt.elements(data_form.NS_X_DATA,'x').next() 249 x_elt = command_elt.elements(data_form.NS_X_DATA, "x").next()
187 answer_form = data_form.Form.fromElement(x_elt) 250 answer_form = data_form.Form.fromElement(x_elt)
188 command = answer_form['command'] 251 command = answer_form["command"]
189 except (KeyError, StopIteration): 252 except (KeyError, StopIteration):
190 raise self.XEP_0050.AdHocError(self.XEP_0050.ERROR.BAD_PAYLOAD) 253 raise self.XEP_0050.AdHocError(self.XEP_0050.ERROR.BAD_PAYLOAD)
191 254
192 if command not in names_map: 255 if command not in names_map:
193 raise self.XEP_0050.AdHocError(self.XEP_0050.ERROR.BAD_PAYLOAD) 256 raise self.XEP_0050.AdHocError(self.XEP_0050.ERROR.BAD_PAYLOAD)
200 # job done, we can end the session, except if we have FLAG_LOOP 263 # job done, we can end the session, except if we have FLAG_LOOP
201 if FLAG_LOOP in flags: 264 if FLAG_LOOP in flags:
202 # We have a loop, so we clear everything and we execute again the command as we had a first call (command_elt is not used, so None is OK) 265 # We have a loop, so we clear everything and we execute again the command as we had a first call (command_elt is not used, so None is OK)
203 del actions[:] 266 del actions[:]
204 names_map.clear() 267 names_map.clear()
205 return DBusCallback(None, session_data, self.XEP_0050.ACTION.EXECUTE, node, profile) 268 return DBusCallback(
206 form = data_form.Form('form', title=_(u'Updated')) 269 None, session_data, self.XEP_0050.ACTION.EXECUTE, node, profile
207 form.addField(data_form.Field('fixed', u'Command sent')) 270 )
271 form = data_form.Form("form", title=_(u"Updated"))
272 form.addField(data_form.Field("fixed", u"Command sent"))
208 status = self.XEP_0050.STATUS.COMPLETED 273 status = self.XEP_0050.STATUS.COMPLETED
209 payload = None 274 payload = None
210 note = (self.XEP_0050.NOTE.INFO, _(u"Command sent")) 275 note = (self.XEP_0050.NOTE.INFO, _(u"Command sent"))
211 else: 276 else:
212 raise self.XEP_0050.AdHocError(self.XEP_0050.ERROR.INTERNAL) 277 raise self.XEP_0050.AdHocError(self.XEP_0050.ERROR.INTERNAL)
213 278
214 return (payload, status, None, note) 279 return (payload, status, None, note)
215 280
216 self.XEP_0050.addAdHocCommand(DBusCallback, adhoc_name, 281 self.XEP_0050.addAdHocCommand(
217 allowed_jids = allowed_jids, 282 DBusCallback,
218 allowed_groups = allowed_groups, 283 adhoc_name,
219 allowed_magics = allowed_magics, 284 allowed_jids=allowed_jids,
220 forbidden_jids = forbidden_jids, 285 allowed_groups=allowed_groups,
221 forbidden_groups = forbidden_groups, 286 allowed_magics=allowed_magics,
222 profile_key = profile_key) 287 forbidden_jids=forbidden_jids,
288 forbidden_groups=forbidden_groups,
289 profile_key=profile_key,
290 )