Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0096.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 | 849374e59178 |
children |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
62 self.host.plugins["XEP-0047"].NAMESPACE, | 62 self.host.plugins["XEP-0047"].NAMESPACE, |
63 ] # Stream methods managed | 63 ] # Stream methods managed |
64 self._f = self.host.plugins["FILE"] | 64 self._f = self.host.plugins["FILE"] |
65 self._f.register(self) | 65 self._f.register(self) |
66 self._si = self.host.plugins["XEP-0095"] | 66 self._si = self.host.plugins["XEP-0095"] |
67 self._si.registerSIProfile(SI_PROFILE_NAME, self._transferRequest) | 67 self._si.register_si_profile(SI_PROFILE_NAME, self._transfer_request) |
68 host.bridge.addMethod( | 68 host.bridge.add_method( |
69 "siSendFile", ".plugin", in_sign="sssss", out_sign="s", method=self._fileSend | 69 "si_file_send", ".plugin", in_sign="sssss", out_sign="s", method=self._file_send |
70 ) | 70 ) |
71 | 71 |
72 async def canHandleFileSend(self, client, peer_jid, filepath): | 72 async def can_handle_file_send(self, client, peer_jid, filepath): |
73 return await self.host.hasFeature(client, NS_SI_FT, peer_jid) | 73 return await self.host.hasFeature(client, NS_SI_FT, peer_jid) |
74 | 74 |
75 def unload(self): | 75 def unload(self): |
76 self._si.unregisterSIProfile(SI_PROFILE_NAME) | 76 self._si.unregister_si_profile(SI_PROFILE_NAME) |
77 | 77 |
78 def _badRequest(self, client, iq_elt, message=None): | 78 def _bad_request(self, client, iq_elt, message=None): |
79 """Send a bad-request error | 79 """Send a bad-request error |
80 | 80 |
81 @param iq_elt(domish.Element): initial <IQ> element of the SI request | 81 @param iq_elt(domish.Element): initial <IQ> element of the SI request |
82 @param message(None, unicode): informational message to display in the logs | 82 @param message(None, unicode): informational message to display in the logs |
83 """ | 83 """ |
84 if message is not None: | 84 if message is not None: |
85 log.warning(message) | 85 log.warning(message) |
86 self._si.sendError(client, iq_elt, "bad-request") | 86 self._si.sendError(client, iq_elt, "bad-request") |
87 | 87 |
88 def _parseRange(self, parent_elt, file_size): | 88 def _parse_range(self, parent_elt, file_size): |
89 """find and parse <range/> element | 89 """find and parse <range/> element |
90 | 90 |
91 @param parent_elt(domish.Element): direct parent of the <range/> element | 91 @param parent_elt(domish.Element): direct parent of the <range/> element |
92 @return (tuple[bool, int, int]): a tuple with | 92 @return (tuple[bool, int, int]): a tuple with |
93 - True if range is required | 93 - True if range is required |
116 if range_offset != 0 or range_length != file_size: | 116 if range_offset != 0 or range_length != file_size: |
117 raise NotImplementedError # FIXME | 117 raise NotImplementedError # FIXME |
118 | 118 |
119 return range_, range_offset, range_length | 119 return range_, range_offset, range_length |
120 | 120 |
121 def _transferRequest(self, client, iq_elt, si_id, si_mime_type, si_elt): | 121 def _transfer_request(self, client, iq_elt, si_id, si_mime_type, si_elt): |
122 """Called when a file transfer is requested | 122 """Called when a file transfer is requested |
123 | 123 |
124 @param iq_elt(domish.Element): initial <IQ> element of the SI request | 124 @param iq_elt(domish.Element): initial <IQ> element of the SI request |
125 @param si_id(unicode): Stream Initiation session id | 125 @param si_id(unicode): Stream Initiation session id |
126 @param si_mime_type("unicode"): Mime type of the file (or default "application/octet-stream" if unknown) | 126 @param si_mime_type("unicode"): Mime type of the file (or default "application/octet-stream" if unknown) |
130 peer_jid = jid.JID(iq_elt["from"]) | 130 peer_jid = jid.JID(iq_elt["from"]) |
131 | 131 |
132 try: | 132 try: |
133 file_elt = next(si_elt.elements(NS_SI_FT, "file")) | 133 file_elt = next(si_elt.elements(NS_SI_FT, "file")) |
134 except StopIteration: | 134 except StopIteration: |
135 return self._badRequest( | 135 return self._bad_request( |
136 client, iq_elt, "No <file/> element found in SI File Transfer request" | 136 client, iq_elt, "No <file/> element found in SI File Transfer request" |
137 ) | 137 ) |
138 | 138 |
139 try: | 139 try: |
140 feature_elt = self.host.plugins["XEP-0020"].getFeatureElt(si_elt) | 140 feature_elt = self.host.plugins["XEP-0020"].get_feature_elt(si_elt) |
141 except exceptions.NotFound: | 141 except exceptions.NotFound: |
142 return self._badRequest( | 142 return self._bad_request( |
143 client, iq_elt, "No <feature/> element found in SI File Transfer request" | 143 client, iq_elt, "No <feature/> element found in SI File Transfer request" |
144 ) | 144 ) |
145 | 145 |
146 try: | 146 try: |
147 filename = file_elt["name"] | 147 filename = file_elt["name"] |
148 file_size = int(file_elt["size"]) | 148 file_size = int(file_elt["size"]) |
149 except (KeyError, ValueError): | 149 except (KeyError, ValueError): |
150 return self._badRequest(client, iq_elt, "Malformed SI File Transfer request") | 150 return self._bad_request(client, iq_elt, "Malformed SI File Transfer request") |
151 | 151 |
152 file_date = file_elt.getAttribute("date") | 152 file_date = file_elt.getAttribute("date") |
153 file_hash = file_elt.getAttribute("hash") | 153 file_hash = file_elt.getAttribute("hash") |
154 | 154 |
155 log.info( | 155 log.info( |
162 file_desc = str(next(file_elt.elements(NS_SI_FT, "desc"))) | 162 file_desc = str(next(file_elt.elements(NS_SI_FT, "desc"))) |
163 except StopIteration: | 163 except StopIteration: |
164 file_desc = "" | 164 file_desc = "" |
165 | 165 |
166 try: | 166 try: |
167 range_, range_offset, range_length = self._parseRange(file_elt, file_size) | 167 range_, range_offset, range_length = self._parse_range(file_elt, file_size) |
168 except ValueError: | 168 except ValueError: |
169 return self._badRequest(client, iq_elt, "Malformed SI File Transfer request") | 169 return self._bad_request(client, iq_elt, "Malformed SI File Transfer request") |
170 | 170 |
171 try: | 171 try: |
172 stream_method = self.host.plugins["XEP-0020"].negotiate( | 172 stream_method = self.host.plugins["XEP-0020"].negotiate( |
173 feature_elt, "stream-method", self.managed_stream_m, namespace=None | 173 feature_elt, "stream-method", self.managed_stream_m, namespace=None |
174 ) | 174 ) |
175 except KeyError: | 175 except KeyError: |
176 return self._badRequest(client, iq_elt, "No stream method found") | 176 return self._bad_request(client, iq_elt, "No stream method found") |
177 | 177 |
178 if stream_method: | 178 if stream_method: |
179 if stream_method == self.host.plugins["XEP-0065"].NAMESPACE: | 179 if stream_method == self.host.plugins["XEP-0065"].NAMESPACE: |
180 plugin = self.host.plugins["XEP-0065"] | 180 plugin = self.host.plugins["XEP-0065"] |
181 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: | 181 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: |
205 "stream_method": stream_method, | 205 "stream_method": stream_method, |
206 "stream_plugin": plugin, | 206 "stream_plugin": plugin, |
207 } | 207 } |
208 | 208 |
209 d = defer.ensureDeferred( | 209 d = defer.ensureDeferred( |
210 self._f.getDestDir(client, peer_jid, data, data, stream_object=True) | 210 self._f.get_dest_dir(client, peer_jid, data, data, stream_object=True) |
211 ) | 211 ) |
212 d.addCallback(self.confirmationCb, client, iq_elt, data) | 212 d.addCallback(self.confirmation_cb, client, iq_elt, data) |
213 | 213 |
214 def confirmationCb(self, accepted, client, iq_elt, data): | 214 def confirmation_cb(self, accepted, client, iq_elt, data): |
215 """Called on confirmation answer | 215 """Called on confirmation answer |
216 | 216 |
217 @param accepted(bool): True if file transfer is accepted | 217 @param accepted(bool): True if file transfer is accepted |
218 @param iq_elt(domish.Element): initial SI request | 218 @param iq_elt(domish.Element): initial SI request |
219 @param data(dict): session data | 219 @param data(dict): session data |
242 # del client._xep_0096_waiting_for_approval[sid] | 242 # del client._xep_0096_waiting_for_approval[sid] |
243 # return | 243 # return |
244 | 244 |
245 # file_obj = self._getFileObject(dest_path, can_range) | 245 # file_obj = self._getFileObject(dest_path, can_range) |
246 # range_offset = file_obj.tell() | 246 # range_offset = file_obj.tell() |
247 d = data["stream_plugin"].createSession( | 247 d = data["stream_plugin"].create_session( |
248 client, data["stream_object"], client.jid, data["peer_jid"], data["si_id"] | 248 client, data["stream_object"], client.jid, data["peer_jid"], data["si_id"] |
249 ) | 249 ) |
250 d.addCallback(self._transferCb, client, data) | 250 d.addCallback(self._transfer_cb, client, data) |
251 d.addErrback(self._transferEb, client, data) | 251 d.addErrback(self._transfer_eb, client, data) |
252 | 252 |
253 # we can send the iq result | 253 # we can send the iq result |
254 feature_elt = self.host.plugins["XEP-0020"].chooseOption( | 254 feature_elt = self.host.plugins["XEP-0020"].choose_option( |
255 {"stream-method": data["stream_method"]}, namespace=None | 255 {"stream-method": data["stream_method"]}, namespace=None |
256 ) | 256 ) |
257 misc_elts = [] | 257 misc_elts = [] |
258 misc_elts.append(domish.Element((SI_PROFILE, "file"))) | 258 misc_elts.append(domish.Element((SI_PROFILE, "file"))) |
259 # if can_range: | 259 # if can_range: |
260 # range_elt = domish.Element((None, "range")) | 260 # range_elt = domish.Element((None, "range")) |
261 # range_elt['offset'] = str(range_offset) | 261 # range_elt['offset'] = str(range_offset) |
262 # #TODO: manage range length | 262 # #TODO: manage range length |
263 # misc_elts.append(range_elt) | 263 # misc_elts.append(range_elt) |
264 self._si.acceptStream(client, iq_elt, feature_elt, misc_elts) | 264 self._si.accept_stream(client, iq_elt, feature_elt, misc_elts) |
265 | 265 |
266 def _transferCb(self, __, client, data): | 266 def _transfer_cb(self, __, client, data): |
267 """Called by the stream method when transfer successfuly finished | 267 """Called by the stream method when transfer successfuly finished |
268 | 268 |
269 @param data: session data | 269 @param data: session data |
270 """ | 270 """ |
271 # TODO: check hash | 271 # TODO: check hash |
272 data["stream_object"].close() | 272 data["stream_object"].close() |
273 log.info("Transfer {si_id} successfuly finished".format(**data)) | 273 log.info("Transfer {si_id} successfuly finished".format(**data)) |
274 | 274 |
275 def _transferEb(self, failure, client, data): | 275 def _transfer_eb(self, failure, client, data): |
276 """Called when something went wrong with the transfer | 276 """Called when something went wrong with the transfer |
277 | 277 |
278 @param id: stream id | 278 @param id: stream id |
279 @param data: session data | 279 @param data: session data |
280 """ | 280 """ |
283 reason=str(failure.value), **data | 283 reason=str(failure.value), **data |
284 ) | 284 ) |
285 ) | 285 ) |
286 data["stream_object"].close() | 286 data["stream_object"].close() |
287 | 287 |
288 def _fileSend(self, peer_jid_s, filepath, name, desc, profile=C.PROF_KEY_NONE): | 288 def _file_send(self, peer_jid_s, filepath, name, desc, profile=C.PROF_KEY_NONE): |
289 client = self.host.getClient(profile) | 289 client = self.host.get_client(profile) |
290 return self.fileSend( | 290 return self.file_send( |
291 client, jid.JID(peer_jid_s), filepath, name or None, desc or None | 291 client, jid.JID(peer_jid_s), filepath, name or None, desc or None |
292 ) | 292 ) |
293 | 293 |
294 def fileSend(self, client, peer_jid, filepath, name=None, desc=None, extra=None): | 294 def file_send(self, client, peer_jid, filepath, name=None, desc=None, extra=None): |
295 """Send a file using XEP-0096 | 295 """Send a file using XEP-0096 |
296 | 296 |
297 @param peer_jid(jid.JID): recipient | 297 @param peer_jid(jid.JID): recipient |
298 @param filepath(str): absolute path to the file to send | 298 @param filepath(str): absolute path to the file to send |
299 @param name(unicode): name of the file to send | 299 @param name(unicode): name of the file to send |
300 name must not contain "/" characters | 300 name must not contain "/" characters |
301 @param desc: description of the file | 301 @param desc: description of the file |
302 @param extra: not used here | 302 @param extra: not used here |
303 @return: an unique id to identify the transfer | 303 @return: an unique id to identify the transfer |
304 """ | 304 """ |
305 feature_elt = self.host.plugins["XEP-0020"].proposeFeatures( | 305 feature_elt = self.host.plugins["XEP-0020"].propose_features( |
306 {"stream-method": self.managed_stream_m}, namespace=None | 306 {"stream-method": self.managed_stream_m}, namespace=None |
307 ) | 307 ) |
308 | 308 |
309 file_transfer_elts = [] | 309 file_transfer_elts = [] |
310 | 310 |
318 file_elt.addElement("desc", content=desc) | 318 file_elt.addElement("desc", content=desc) |
319 file_transfer_elts.append(file_elt) | 319 file_transfer_elts.append(file_elt) |
320 | 320 |
321 file_transfer_elts.append(domish.Element((None, "range"))) | 321 file_transfer_elts.append(domish.Element((None, "range"))) |
322 | 322 |
323 sid, offer_d = self._si.proposeStream( | 323 sid, offer_d = self._si.propose_stream( |
324 client, peer_jid, SI_PROFILE, feature_elt, file_transfer_elts | 324 client, peer_jid, SI_PROFILE, feature_elt, file_transfer_elts |
325 ) | 325 ) |
326 args = [filepath, sid, size, client] | 326 args = [filepath, sid, size, client] |
327 offer_d.addCallbacks(self._fileCb, self._fileEb, args, None, args) | 327 offer_d.addCallbacks(self._file_cb, self._file_eb, args, None, args) |
328 return sid | 328 return sid |
329 | 329 |
330 def _fileCb(self, result_tuple, filepath, sid, size, client): | 330 def _file_cb(self, result_tuple, filepath, sid, size, client): |
331 iq_elt, si_elt = result_tuple | 331 iq_elt, si_elt = result_tuple |
332 | 332 |
333 try: | 333 try: |
334 feature_elt = self.host.plugins["XEP-0020"].getFeatureElt(si_elt) | 334 feature_elt = self.host.plugins["XEP-0020"].get_feature_elt(si_elt) |
335 except exceptions.NotFound: | 335 except exceptions.NotFound: |
336 log.warning("No <feature/> element found in result while expected") | 336 log.warning("No <feature/> element found in result while expected") |
337 return | 337 return |
338 | 338 |
339 choosed_options = self.host.plugins["XEP-0020"].getChoosedOptions( | 339 choosed_options = self.host.plugins["XEP-0020"].get_choosed_options( |
340 feature_elt, namespace=None | 340 feature_elt, namespace=None |
341 ) | 341 ) |
342 try: | 342 try: |
343 stream_method = choosed_options["stream-method"] | 343 stream_method = choosed_options["stream-method"] |
344 except KeyError: | 344 except KeyError: |
348 try: | 348 try: |
349 file_elt = next(si_elt.elements(NS_SI_FT, "file")) | 349 file_elt = next(si_elt.elements(NS_SI_FT, "file")) |
350 except StopIteration: | 350 except StopIteration: |
351 pass | 351 pass |
352 else: | 352 else: |
353 range_, range_offset, range_length = self._parseRange(file_elt, size) | 353 range_, range_offset, range_length = self._parse_range(file_elt, size) |
354 | 354 |
355 if stream_method == self.host.plugins["XEP-0065"].NAMESPACE: | 355 if stream_method == self.host.plugins["XEP-0065"].NAMESPACE: |
356 plugin = self.host.plugins["XEP-0065"] | 356 plugin = self.host.plugins["XEP-0065"] |
357 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: | 357 elif stream_method == self.host.plugins["XEP-0047"].NAMESPACE: |
358 plugin = self.host.plugins["XEP-0047"] | 358 plugin = self.host.plugins["XEP-0047"] |
361 return | 361 return |
362 | 362 |
363 stream_object = stream.FileStreamObject( | 363 stream_object = stream.FileStreamObject( |
364 self.host, client, filepath, uid=sid, size=size | 364 self.host, client, filepath, uid=sid, size=size |
365 ) | 365 ) |
366 d = plugin.startStream(client, stream_object, client.jid, | 366 d = plugin.start_stream(client, stream_object, client.jid, |
367 jid.JID(iq_elt["from"]), sid) | 367 jid.JID(iq_elt["from"]), sid) |
368 d.addCallback(self._sendCb, client, sid, stream_object) | 368 d.addCallback(self._send_cb, client, sid, stream_object) |
369 d.addErrback(self._sendEb, client, sid, stream_object) | 369 d.addErrback(self._send_eb, client, sid, stream_object) |
370 | 370 |
371 def _fileEb(self, failure, filepath, sid, size, client): | 371 def _file_eb(self, failure, filepath, sid, size, client): |
372 if failure.check(error.StanzaError): | 372 if failure.check(error.StanzaError): |
373 stanza_err = failure.value | 373 stanza_err = failure.value |
374 if stanza_err.code == "403" and stanza_err.condition == "forbidden": | 374 if stanza_err.code == "403" and stanza_err.condition == "forbidden": |
375 from_s = stanza_err.stanza["from"] | 375 from_s = stanza_err.stanza["from"] |
376 log.info("File transfer refused by {}".format(from_s)) | 376 log.info("File transfer refused by {}".format(from_s)) |
377 msg = D_("The contact {} has refused your file").format(from_s) | 377 msg = D_("The contact {} has refused your file").format(from_s) |
378 title = D_("File refused") | 378 title = D_("File refused") |
379 xml_tools.quickNote(self.host, client, msg, title, C.XMLUI_DATA_LVL_INFO) | 379 xml_tools.quick_note(self.host, client, msg, title, C.XMLUI_DATA_LVL_INFO) |
380 else: | 380 else: |
381 log.warning(_("Error during file transfer")) | 381 log.warning(_("Error during file transfer")) |
382 msg = D_( | 382 msg = D_( |
383 "Something went wrong during the file transfer session initialisation: {reason}" | 383 "Something went wrong during the file transfer session initialisation: {reason}" |
384 ).format(reason=str(stanza_err)) | 384 ).format(reason=str(stanza_err)) |
385 title = D_("File transfer error") | 385 title = D_("File transfer error") |
386 xml_tools.quickNote(self.host, client, msg, title, C.XMLUI_DATA_LVL_ERROR) | 386 xml_tools.quick_note(self.host, client, msg, title, C.XMLUI_DATA_LVL_ERROR) |
387 elif failure.check(exceptions.DataError): | 387 elif failure.check(exceptions.DataError): |
388 log.warning("Invalid stanza received") | 388 log.warning("Invalid stanza received") |
389 else: | 389 else: |
390 log.error("Error while proposing stream: {}".format(failure)) | 390 log.error("Error while proposing stream: {}".format(failure)) |
391 | 391 |
392 def _sendCb(self, __, client, sid, stream_object): | 392 def _send_cb(self, __, client, sid, stream_object): |
393 log.info( | 393 log.info( |
394 _("transfer {sid} successfuly finished [{profile}]").format( | 394 _("transfer {sid} successfuly finished [{profile}]").format( |
395 sid=sid, profile=client.profile | 395 sid=sid, profile=client.profile |
396 ) | 396 ) |
397 ) | 397 ) |
398 stream_object.close() | 398 stream_object.close() |
399 | 399 |
400 def _sendEb(self, failure, client, sid, stream_object): | 400 def _send_eb(self, failure, client, sid, stream_object): |
401 log.warning( | 401 log.warning( |
402 _("transfer {sid} failed [{profile}]: {reason}").format( | 402 _("transfer {sid} failed [{profile}]: {reason}").format( |
403 sid=sid, profile=client.profile, reason=str(failure.value) | 403 sid=sid, profile=client.profile, reason=str(failure.value) |
404 ) | 404 ) |
405 ) | 405 ) |