Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0234.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 | 8e7d5796fb23 |
children | 2ced30f6d5de |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
69 human_name = D_("file transfer") | 69 human_name = D_("file transfer") |
70 | 70 |
71 def __init__(self, host): | 71 def __init__(self, host): |
72 log.info(_("plugin Jingle File Transfer initialization")) | 72 log.info(_("plugin Jingle File Transfer initialization")) |
73 self.host = host | 73 self.host = host |
74 host.registerNamespace("jingle-ft", NS_JINGLE_FT) | 74 host.register_namespace("jingle-ft", NS_JINGLE_FT) |
75 self._j = host.plugins["XEP-0166"] # shortcut to access jingle | 75 self._j = host.plugins["XEP-0166"] # shortcut to access jingle |
76 self._j.registerApplication(NS_JINGLE_FT, self) | 76 self._j.register_application(NS_JINGLE_FT, self) |
77 self._f = host.plugins["FILE"] | 77 self._f = host.plugins["FILE"] |
78 self._f.register(self, priority=10000) | 78 self._f.register(self, priority=10000) |
79 self._hash = self.host.plugins["XEP-0300"] | 79 self._hash = self.host.plugins["XEP-0300"] |
80 host.bridge.addMethod( | 80 host.bridge.add_method( |
81 "fileJingleSend", | 81 "file_jingle_send", |
82 ".plugin", | 82 ".plugin", |
83 in_sign="ssssa{ss}s", | 83 in_sign="ssssa{ss}s", |
84 out_sign="", | 84 out_sign="", |
85 method=self._fileSend, | 85 method=self._file_send, |
86 async_=True, | 86 async_=True, |
87 ) | 87 ) |
88 host.bridge.addMethod( | 88 host.bridge.add_method( |
89 "fileJingleRequest", | 89 "file_jingle_request", |
90 ".plugin", | 90 ".plugin", |
91 in_sign="sssssa{ss}s", | 91 in_sign="sssssa{ss}s", |
92 out_sign="s", | 92 out_sign="s", |
93 method=self._fileJingleRequest, | 93 method=self._file_jingle_request, |
94 async_=True, | 94 async_=True, |
95 ) | 95 ) |
96 | 96 |
97 def getHandler(self, client): | 97 def get_handler(self, client): |
98 return XEP_0234_handler() | 98 return XEP_0234_handler() |
99 | 99 |
100 def getProgressId(self, session, content_name): | 100 def get_progress_id(self, session, content_name): |
101 """Return a unique progress ID | 101 """Return a unique progress ID |
102 | 102 |
103 @param session(dict): jingle session | 103 @param session(dict): jingle session |
104 @param content_name(unicode): name of the content | 104 @param content_name(unicode): name of the content |
105 @return (unicode): unique progress id | 105 @return (unicode): unique progress id |
106 """ | 106 """ |
107 return "{}_{}".format(session["id"], content_name) | 107 return "{}_{}".format(session["id"], content_name) |
108 | 108 |
109 async def canHandleFileSend(self, client, peer_jid, filepath): | 109 async def can_handle_file_send(self, client, peer_jid, filepath): |
110 if peer_jid.resource: | 110 if peer_jid.resource: |
111 return await self.host.hasFeature(client, NS_JINGLE_FT, peer_jid) | 111 return await self.host.hasFeature(client, NS_JINGLE_FT, peer_jid) |
112 else: | 112 else: |
113 # if we have a bare jid, Jingle Message Initiation will be tried | 113 # if we have a bare jid, Jingle Message Initiation will be tried |
114 return True | 114 return True |
115 | 115 |
116 # generic methods | 116 # generic methods |
117 | 117 |
118 def buildFileElement( | 118 def build_file_element( |
119 self, client, name=None, file_hash=None, hash_algo=None, size=None, | 119 self, client, name=None, file_hash=None, hash_algo=None, size=None, |
120 mime_type=None, desc=None, modified=None, transfer_range=None, path=None, | 120 mime_type=None, desc=None, modified=None, transfer_range=None, path=None, |
121 namespace=None, file_elt=None, **kwargs): | 121 namespace=None, file_elt=None, **kwargs): |
122 """Generate a <file> element with available metadata | 122 """Generate a <file> element with available metadata |
123 | 123 |
166 range_elt["offset"] = transfer_range.offset | 166 range_elt["offset"] = transfer_range.offset |
167 if transfer_range.length is not None: | 167 if transfer_range.length is not None: |
168 range_elt["length"] = transfer_range.length | 168 range_elt["length"] = transfer_range.length |
169 if file_hash is not None: | 169 if file_hash is not None: |
170 if not file_hash: | 170 if not file_hash: |
171 file_elt.addChild(self._hash.buildHashUsedElt()) | 171 file_elt.addChild(self._hash.build_hash_used_elt()) |
172 else: | 172 else: |
173 file_elt.addChild(self._hash.buildHashElt(file_hash, hash_algo)) | 173 file_elt.addChild(self._hash.build_hash_elt(file_hash, hash_algo)) |
174 elif hash_algo is not None: | 174 elif hash_algo is not None: |
175 file_elt.addChild(self._hash.buildHashUsedElt(hash_algo)) | 175 file_elt.addChild(self._hash.build_hash_used_elt(hash_algo)) |
176 self.host.trigger.point( | 176 self.host.trigger.point( |
177 "XEP-0234_buildFileElement", client, file_elt, extra_args=kwargs) | 177 "XEP-0234_buildFileElement", client, file_elt, extra_args=kwargs) |
178 if kwargs: | 178 if kwargs: |
179 for kw in kwargs: | 179 for kw in kwargs: |
180 log.debug("ignored keyword: {}".format(kw)) | 180 log.debug("ignored keyword: {}".format(kw)) |
181 return file_elt | 181 return file_elt |
182 | 182 |
183 def buildFileElementFromDict(self, client, file_data, **kwargs): | 183 def build_file_element_from_dict(self, client, file_data, **kwargs): |
184 """like buildFileElement but get values from a file_data dict | 184 """like build_file_element but get values from a file_data dict |
185 | 185 |
186 @param file_data(dict): metadata to use | 186 @param file_data(dict): metadata to use |
187 @param **kwargs: data to override | 187 @param **kwargs: data to override |
188 """ | 188 """ |
189 if kwargs: | 189 if kwargs: |
193 file_data["mime_type"] = ( | 193 file_data["mime_type"] = ( |
194 f'{file_data.pop("media_type")}/{file_data.pop("media_subtype")}' | 194 f'{file_data.pop("media_type")}/{file_data.pop("media_subtype")}' |
195 ) | 195 ) |
196 except KeyError: | 196 except KeyError: |
197 pass | 197 pass |
198 return self.buildFileElement(client, **file_data) | 198 return self.build_file_element(client, **file_data) |
199 | 199 |
200 async def parseFileElement( | 200 async def parse_file_element( |
201 self, client, file_elt, file_data=None, given=False, parent_elt=None, | 201 self, client, file_elt, file_data=None, given=False, parent_elt=None, |
202 keep_empty_range=False): | 202 keep_empty_range=False): |
203 """Parse a <file> element and file dictionary accordingly | 203 """Parse a <file> element and file dictionary accordingly |
204 | 204 |
205 @param file_data(dict, None): dict where the data will be set | 205 @param file_data(dict, None): dict where the data will be set |
246 if name == "..": | 246 if name == "..": |
247 # we don't want to go to parent dir when joining to a path | 247 # we don't want to go to parent dir when joining to a path |
248 name = "--" | 248 name = "--" |
249 file_data["name"] = name | 249 file_data["name"] = name |
250 elif name is not None and ("/" in name or "\\" in name): | 250 elif name is not None and ("/" in name or "\\" in name): |
251 file_data["name"] = regex.pathEscape(name) | 251 file_data["name"] = regex.path_escape(name) |
252 | 252 |
253 try: | 253 try: |
254 file_data["mime_type"] = str( | 254 file_data["mime_type"] = str( |
255 next(file_elt.elements(NS_JINGLE_FT, "media-type")) | 255 next(file_elt.elements(NS_JINGLE_FT, "media-type")) |
256 ) | 256 ) |
282 file_data["transfer_range"] = Range(offset=offset, length=length) | 282 file_data["transfer_range"] = Range(offset=offset, length=length) |
283 | 283 |
284 prefix = "given_" if given else "" | 284 prefix = "given_" if given else "" |
285 hash_algo_key, hash_key = "hash_algo", prefix + "file_hash" | 285 hash_algo_key, hash_key = "hash_algo", prefix + "file_hash" |
286 try: | 286 try: |
287 file_data[hash_algo_key], file_data[hash_key] = self._hash.parseHashElt( | 287 file_data[hash_algo_key], file_data[hash_key] = self._hash.parse_hash_elt( |
288 file_elt | 288 file_elt |
289 ) | 289 ) |
290 except exceptions.NotFound: | 290 except exceptions.NotFound: |
291 pass | 291 pass |
292 | 292 |
294 | 294 |
295 return file_data | 295 return file_data |
296 | 296 |
297 # bridge methods | 297 # bridge methods |
298 | 298 |
299 def _fileSend( | 299 def _file_send( |
300 self, | 300 self, |
301 peer_jid, | 301 peer_jid, |
302 filepath, | 302 filepath, |
303 name="", | 303 name="", |
304 file_desc="", | 304 file_desc="", |
305 extra=None, | 305 extra=None, |
306 profile=C.PROF_KEY_NONE, | 306 profile=C.PROF_KEY_NONE, |
307 ): | 307 ): |
308 client = self.host.getClient(profile) | 308 client = self.host.get_client(profile) |
309 return defer.ensureDeferred(self.fileSend( | 309 return defer.ensureDeferred(self.file_send( |
310 client, | 310 client, |
311 jid.JID(peer_jid), | 311 jid.JID(peer_jid), |
312 filepath, | 312 filepath, |
313 name or None, | 313 name or None, |
314 file_desc or None, | 314 file_desc or None, |
315 extra or None, | 315 extra or None, |
316 )) | 316 )) |
317 | 317 |
318 async def fileSend( | 318 async def file_send( |
319 self, client, peer_jid, filepath, name, file_desc=None, extra=None | 319 self, client, peer_jid, filepath, name, file_desc=None, extra=None |
320 ): | 320 ): |
321 """Send a file using jingle file transfer | 321 """Send a file using jingle file transfer |
322 | 322 |
323 @param peer_jid(jid.JID): destinee jid | 323 @param peer_jid(jid.JID): destinee jid |
349 ], | 349 ], |
350 encrypted = encrypted | 350 encrypted = encrypted |
351 ) | 351 ) |
352 return await progress_id_d | 352 return await progress_id_d |
353 | 353 |
354 def _fileJingleRequest( | 354 def _file_jingle_request( |
355 self, peer_jid, filepath, name="", file_hash="", hash_algo="", extra=None, | 355 self, peer_jid, filepath, name="", file_hash="", hash_algo="", extra=None, |
356 profile=C.PROF_KEY_NONE): | 356 profile=C.PROF_KEY_NONE): |
357 client = self.host.getClient(profile) | 357 client = self.host.get_client(profile) |
358 return defer.ensureDeferred(self.fileJingleRequest( | 358 return defer.ensureDeferred(self.file_jingle_request( |
359 client, | 359 client, |
360 jid.JID(peer_jid), | 360 jid.JID(peer_jid), |
361 filepath, | 361 filepath, |
362 name or None, | 362 name or None, |
363 file_hash or None, | 363 file_hash or None, |
364 hash_algo or None, | 364 hash_algo or None, |
365 extra or None, | 365 extra or None, |
366 )) | 366 )) |
367 | 367 |
368 async def fileJingleRequest( | 368 async def file_jingle_request( |
369 self, client, peer_jid, filepath, name=None, file_hash=None, hash_algo=None, | 369 self, client, peer_jid, filepath, name=None, file_hash=None, hash_algo=None, |
370 extra=None): | 370 extra=None): |
371 """Request a file using jingle file transfer | 371 """Request a file using jingle file transfer |
372 | 372 |
373 @param peer_jid(jid.JID): destinee jid | 373 @param peer_jid(jid.JID): destinee jid |
405 ) | 405 ) |
406 return await progress_id_d | 406 return await progress_id_d |
407 | 407 |
408 # jingle callbacks | 408 # jingle callbacks |
409 | 409 |
410 def jingleDescriptionElt( | 410 def jingle_description_elt( |
411 self, client, session, content_name, filepath, name, extra, progress_id_d | 411 self, client, session, content_name, filepath, name, extra, progress_id_d |
412 ): | 412 ): |
413 return domish.Element((NS_JINGLE_FT, "description")) | 413 return domish.Element((NS_JINGLE_FT, "description")) |
414 | 414 |
415 def jingleSessionInit( | 415 def jingle_session_init( |
416 self, client, session, content_name, filepath, name, extra, progress_id_d | 416 self, client, session, content_name, filepath, name, extra, progress_id_d |
417 ): | 417 ): |
418 if extra is None: | 418 if extra is None: |
419 extra = {} | 419 extra = {} |
420 else: | 420 else: |
422 raise ValueError( | 422 raise ValueError( |
423 _("only the following keys are allowed in extra: {keys}").format( | 423 _("only the following keys are allowed in extra: {keys}").format( |
424 keys=", ".join(EXTRA_ALLOWED) | 424 keys=", ".join(EXTRA_ALLOWED) |
425 ) | 425 ) |
426 ) | 426 ) |
427 progress_id_d.callback(self.getProgressId(session, content_name)) | 427 progress_id_d.callback(self.get_progress_id(session, content_name)) |
428 content_data = session["contents"][content_name] | 428 content_data = session["contents"][content_name] |
429 application_data = content_data["application_data"] | 429 application_data = content_data["application_data"] |
430 assert "file_path" not in application_data | 430 assert "file_path" not in application_data |
431 application_data["file_path"] = filepath | 431 application_data["file_path"] = filepath |
432 file_data = application_data["file_data"] = {} | 432 file_data = application_data["file_data"] = {} |
433 desc_elt = self.jingleDescriptionElt( | 433 desc_elt = self.jingle_description_elt( |
434 client, session, content_name, filepath, name, extra, progress_id_d) | 434 client, session, content_name, filepath, name, extra, progress_id_d) |
435 file_elt = desc_elt.addElement("file") | 435 file_elt = desc_elt.addElement("file") |
436 | 436 |
437 if content_data["senders"] == self._j.ROLE_INITIATOR: | 437 if content_data["senders"] == self._j.ROLE_INITIATOR: |
438 # we send a file | 438 # we send a file |
447 file_data["size"] = os.path.getsize(filepath) | 447 file_data["size"] = os.path.getsize(filepath) |
448 if "namespace" in extra: | 448 if "namespace" in extra: |
449 file_data["namespace"] = extra["namespace"] | 449 file_data["namespace"] = extra["namespace"] |
450 if "path" in extra: | 450 if "path" in extra: |
451 file_data["path"] = extra["path"] | 451 file_data["path"] = extra["path"] |
452 self.buildFileElementFromDict( | 452 self.build_file_element_from_dict( |
453 client, file_data, file_elt=file_elt, file_hash="") | 453 client, file_data, file_elt=file_elt, file_hash="") |
454 else: | 454 else: |
455 # we request a file | 455 # we request a file |
456 file_hash = extra.pop("file_hash", "") | 456 file_hash = extra.pop("file_hash", "") |
457 if not name and not file_hash: | 457 if not name and not file_hash: |
460 file_data["name"] = name | 460 file_data["name"] = name |
461 if file_hash: | 461 if file_hash: |
462 file_data["file_hash"] = file_hash | 462 file_data["file_hash"] = file_hash |
463 file_data["hash_algo"] = extra["hash_algo"] | 463 file_data["hash_algo"] = extra["hash_algo"] |
464 else: | 464 else: |
465 file_data["hash_algo"] = self._hash.getDefaultAlgo() | 465 file_data["hash_algo"] = self._hash.get_default_algo() |
466 if "namespace" in extra: | 466 if "namespace" in extra: |
467 file_data["namespace"] = extra["namespace"] | 467 file_data["namespace"] = extra["namespace"] |
468 if "path" in extra: | 468 if "path" in extra: |
469 file_data["path"] = extra["path"] | 469 file_data["path"] = extra["path"] |
470 self.buildFileElementFromDict(client, file_data, file_elt=file_elt) | 470 self.build_file_element_from_dict(client, file_data, file_elt=file_elt) |
471 | 471 |
472 return desc_elt | 472 return desc_elt |
473 | 473 |
474 async def jingleRequestConfirmation( | 474 async def jingle_request_confirmation( |
475 self, client, action, session, content_name, desc_elt | 475 self, client, action, session, content_name, desc_elt |
476 ): | 476 ): |
477 """This method request confirmation for a jingle session""" | 477 """This method request confirmation for a jingle session""" |
478 content_data = session["contents"][content_name] | 478 content_data = session["contents"][content_name] |
479 senders = content_data["senders"] | 479 senders = content_data["senders"] |
483 # first we grab file informations | 483 # first we grab file informations |
484 try: | 484 try: |
485 file_elt = next(desc_elt.elements(NS_JINGLE_FT, "file")) | 485 file_elt = next(desc_elt.elements(NS_JINGLE_FT, "file")) |
486 except StopIteration: | 486 except StopIteration: |
487 raise failure.Failure(exceptions.DataError) | 487 raise failure.Failure(exceptions.DataError) |
488 file_data = {"progress_id": self.getProgressId(session, content_name)} | 488 file_data = {"progress_id": self.get_progress_id(session, content_name)} |
489 | 489 |
490 if senders == self._j.ROLE_RESPONDER: | 490 if senders == self._j.ROLE_RESPONDER: |
491 # we send the file | 491 # we send the file |
492 return await self._fileSendingRequestConf( | 492 return await self._file_sending_request_conf( |
493 client, session, content_data, content_name, file_data, file_elt | 493 client, session, content_data, content_name, file_data, file_elt |
494 ) | 494 ) |
495 else: | 495 else: |
496 # we receive the file | 496 # we receive the file |
497 return await self._file_receiving_request_conf( | 497 return await self._file_receiving_request_conf( |
498 client, session, content_data, content_name, file_data, file_elt | 498 client, session, content_data, content_name, file_data, file_elt |
499 ) | 499 ) |
500 | 500 |
501 async def _fileSendingRequestConf( | 501 async def _file_sending_request_conf( |
502 self, client, session, content_data, content_name, file_data, file_elt | 502 self, client, session, content_data, content_name, file_data, file_elt |
503 ): | 503 ): |
504 """parse file_elt, and handle file retrieving/permission checking""" | 504 """parse file_elt, and handle file retrieving/permission checking""" |
505 await self.parseFileElement(client, file_elt, file_data) | 505 await self.parse_file_element(client, file_elt, file_data) |
506 content_data["application_data"]["file_data"] = file_data | 506 content_data["application_data"]["file_data"] = file_data |
507 finished_d = content_data["finished_d"] = defer.Deferred() | 507 finished_d = content_data["finished_d"] = defer.Deferred() |
508 | 508 |
509 # confirmed_d is a deferred returning confimed value (only used if cont is False) | 509 # confirmed_d is a deferred returning confimed value (only used if cont is False) |
510 cont, confirmed_d = self.host.trigger.returnPoint( | 510 cont, confirmed_d = self.host.trigger.return_point( |
511 "XEP-0234_fileSendingRequest", | 511 "XEP-0234_fileSendingRequest", |
512 client, | 512 client, |
513 session, | 513 session, |
514 content_data, | 514 content_data, |
515 content_name, | 515 content_name, |
519 if not cont: | 519 if not cont: |
520 confirmed = await confirmed_d | 520 confirmed = await confirmed_d |
521 if confirmed: | 521 if confirmed: |
522 args = [client, session, content_name, content_data] | 522 args = [client, session, content_name, content_data] |
523 finished_d.addCallbacks( | 523 finished_d.addCallbacks( |
524 self._finishedCb, self._finishedEb, args, None, args | 524 self._finished_cb, self._finished_eb, args, None, args |
525 ) | 525 ) |
526 return confirmed | 526 return confirmed |
527 | 527 |
528 log.warning(_("File continue is not implemented yet")) | 528 log.warning(_("File continue is not implemented yet")) |
529 return False | 529 return False |
530 | 530 |
531 async def _file_receiving_request_conf( | 531 async def _file_receiving_request_conf( |
532 self, client, session, content_data, content_name, file_data, file_elt | 532 self, client, session, content_data, content_name, file_data, file_elt |
533 ): | 533 ): |
534 """parse file_elt, and handle user permission/file opening""" | 534 """parse file_elt, and handle user permission/file opening""" |
535 await self.parseFileElement(client, file_elt, file_data, given=True) | 535 await self.parse_file_element(client, file_elt, file_data, given=True) |
536 try: | 536 try: |
537 hash_algo, file_data["given_file_hash"] = self._hash.parseHashElt(file_elt) | 537 hash_algo, file_data["given_file_hash"] = self._hash.parse_hash_elt(file_elt) |
538 except exceptions.NotFound: | 538 except exceptions.NotFound: |
539 try: | 539 try: |
540 hash_algo = self._hash.parseHashUsedElt(file_elt) | 540 hash_algo = self._hash.parse_hash_used_elt(file_elt) |
541 except exceptions.NotFound: | 541 except exceptions.NotFound: |
542 raise failure.Failure(exceptions.DataError) | 542 raise failure.Failure(exceptions.DataError) |
543 | 543 |
544 if hash_algo is not None: | 544 if hash_algo is not None: |
545 file_data["hash_algo"] = hash_algo | 545 file_data["hash_algo"] = hash_algo |
546 file_data["hash_hasher"] = hasher = self._hash.getHasher(hash_algo) | 546 file_data["hash_hasher"] = hasher = self._hash.get_hasher(hash_algo) |
547 file_data["data_cb"] = lambda data: hasher.update(data) | 547 file_data["data_cb"] = lambda data: hasher.update(data) |
548 | 548 |
549 try: | 549 try: |
550 file_data["size"] = int(file_data["size"]) | 550 file_data["size"] = int(file_data["size"]) |
551 except ValueError: | 551 except ValueError: |
562 | 562 |
563 # now we actualy request permission to user | 563 # now we actualy request permission to user |
564 | 564 |
565 # deferred to track end of transfer | 565 # deferred to track end of transfer |
566 finished_d = content_data["finished_d"] = defer.Deferred() | 566 finished_d = content_data["finished_d"] = defer.Deferred() |
567 confirmed = await self._f.getDestDir( | 567 confirmed = await self._f.get_dest_dir( |
568 client, session["peer_jid"], content_data, file_data, stream_object=True | 568 client, session["peer_jid"], content_data, file_data, stream_object=True |
569 ) | 569 ) |
570 if confirmed: | 570 if confirmed: |
571 await self.host.trigger.asyncPoint( | 571 await self.host.trigger.async_point( |
572 "XEP-0234_file_receiving_request_conf", | 572 "XEP-0234_file_receiving_request_conf", |
573 client, session, content_data, file_elt | 573 client, session, content_data, file_elt |
574 ) | 574 ) |
575 args = [client, session, content_name, content_data] | 575 args = [client, session, content_name, content_data] |
576 finished_d.addCallbacks( | 576 finished_d.addCallbacks( |
577 self._finishedCb, self._finishedEb, args, None, args | 577 self._finished_cb, self._finished_eb, args, None, args |
578 ) | 578 ) |
579 return confirmed | 579 return confirmed |
580 | 580 |
581 async def jingleHandler(self, client, action, session, content_name, desc_elt): | 581 async def jingle_handler(self, client, action, session, content_name, desc_elt): |
582 content_data = session["contents"][content_name] | 582 content_data = session["contents"][content_name] |
583 application_data = content_data["application_data"] | 583 application_data = content_data["application_data"] |
584 if action in (self._j.A_ACCEPTED_ACK,): | 584 if action in (self._j.A_ACCEPTED_ACK,): |
585 pass | 585 pass |
586 elif action == self._j.A_SESSION_INITIATE: | 586 elif action == self._j.A_SESSION_INITIATE: |
606 size = int(str(size_elt)) | 606 size = int(str(size_elt)) |
607 except (StopIteration, ValueError): | 607 except (StopIteration, ValueError): |
608 size = None | 608 size = None |
609 # XXX: hash security is not critical here, so we just take the higher | 609 # XXX: hash security is not critical here, so we just take the higher |
610 # mandatory one | 610 # mandatory one |
611 hasher = file_data["hash_hasher"] = self._hash.getHasher() | 611 hasher = file_data["hash_hasher"] = self._hash.get_hasher() |
612 progress_id = self.getProgressId(session, content_name) | 612 progress_id = self.get_progress_id(session, content_name) |
613 try: | 613 try: |
614 content_data["stream_object"] = stream.FileStreamObject( | 614 content_data["stream_object"] = stream.FileStreamObject( |
615 self.host, | 615 self.host, |
616 client, | 616 client, |
617 file_path, | 617 file_path, |
619 uid=progress_id, | 619 uid=progress_id, |
620 size=size, | 620 size=size, |
621 data_cb=lambda data: hasher.update(data), | 621 data_cb=lambda data: hasher.update(data), |
622 ) | 622 ) |
623 except Exception as e: | 623 except Exception as e: |
624 self.host.bridge.progressError( | 624 self.host.bridge.progress_error( |
625 progress_id, C.PROGRESS_ERROR_FAILED, client.profile | 625 progress_id, C.PROGRESS_ERROR_FAILED, client.profile |
626 ) | 626 ) |
627 await self._j.terminate( | 627 await self._j.terminate( |
628 client, self._j.REASON_FAILED_APPLICATION, session) | 628 client, self._j.REASON_FAILED_APPLICATION, session) |
629 raise e | 629 raise e |
630 else: | 630 else: |
631 # we are sending the file | 631 # we are sending the file |
632 size = file_data["size"] | 632 size = file_data["size"] |
633 # XXX: hash security is not critical here, so we just take the higher | 633 # XXX: hash security is not critical here, so we just take the higher |
634 # mandatory one | 634 # mandatory one |
635 hasher = file_data["hash_hasher"] = self._hash.getHasher() | 635 hasher = file_data["hash_hasher"] = self._hash.get_hasher() |
636 content_data["stream_object"] = stream.FileStreamObject( | 636 content_data["stream_object"] = stream.FileStreamObject( |
637 self.host, | 637 self.host, |
638 client, | 638 client, |
639 file_path, | 639 file_path, |
640 uid=self.getProgressId(session, content_name), | 640 uid=self.get_progress_id(session, content_name), |
641 size=size, | 641 size=size, |
642 data_cb=lambda data: hasher.update(data), | 642 data_cb=lambda data: hasher.update(data), |
643 ) | 643 ) |
644 finished_d = content_data["finished_d"] = defer.Deferred() | 644 finished_d = content_data["finished_d"] = defer.Deferred() |
645 args = [client, session, content_name, content_data] | 645 args = [client, session, content_name, content_data] |
646 finished_d.addCallbacks(self._finishedCb, self._finishedEb, args, None, args) | 646 finished_d.addCallbacks(self._finished_cb, self._finished_eb, args, None, args) |
647 await self.host.trigger.asyncPoint( | 647 await self.host.trigger.async_point( |
648 "XEP-0234_jingle_handler", | 648 "XEP-0234_jingle_handler", |
649 client, session, content_data, desc_elt | 649 client, session, content_data, desc_elt |
650 ) | 650 ) |
651 else: | 651 else: |
652 log.warning("FIXME: unmanaged action {}".format(action)) | 652 log.warning("FIXME: unmanaged action {}".format(action)) |
653 return desc_elt | 653 return desc_elt |
654 | 654 |
655 def jingleSessionInfo(self, client, action, session, content_name, jingle_elt): | 655 def jingle_session_info(self, client, action, session, content_name, jingle_elt): |
656 """Called on session-info action | 656 """Called on session-info action |
657 | 657 |
658 manage checksum, and ignore <received/> element | 658 manage checksum, and ignore <received/> element |
659 """ | 659 """ |
660 # TODO: manage <received/> element | 660 # TODO: manage <received/> element |
679 file_data = content_data["application_data"]["file_data"] | 679 file_data = content_data["application_data"]["file_data"] |
680 try: | 680 try: |
681 file_elt = next(elt.elements(NS_JINGLE_FT, "file")) | 681 file_elt = next(elt.elements(NS_JINGLE_FT, "file")) |
682 except StopIteration: | 682 except StopIteration: |
683 raise exceptions.DataError | 683 raise exceptions.DataError |
684 algo, file_data["given_file_hash"] = self._hash.parseHashElt(file_elt) | 684 algo, file_data["given_file_hash"] = self._hash.parse_hash_elt(file_elt) |
685 if algo != file_data.get("hash_algo"): | 685 if algo != file_data.get("hash_algo"): |
686 log.warning( | 686 log.warning( |
687 "Hash algorithm used in given hash ({peer_algo}) doesn't correspond to the one we have used ({our_algo}) [{profile}]".format( | 687 "Hash algorithm used in given hash ({peer_algo}) doesn't correspond to the one we have used ({our_algo}) [{profile}]".format( |
688 peer_algo=algo, | 688 peer_algo=algo, |
689 our_algo=file_data.get("hash_algo"), | 689 our_algo=file_data.get("hash_algo"), |
690 profile=client.profile, | 690 profile=client.profile, |
691 ) | 691 ) |
692 ) | 692 ) |
693 else: | 693 else: |
694 self._receiverTryTerminate( | 694 self._receiver_try_terminate( |
695 client, session, content_name, content_data | 695 client, session, content_name, content_data |
696 ) | 696 ) |
697 else: | 697 else: |
698 raise NotImplementedError | 698 raise NotImplementedError |
699 | 699 |
700 def jingleTerminate(self, client, action, session, content_name, jingle_elt): | 700 def jingle_terminate(self, client, action, session, content_name, jingle_elt): |
701 if jingle_elt.decline: | 701 if jingle_elt.decline: |
702 # progress is the only way to tell to frontends that session has been declined | 702 # progress is the only way to tell to frontends that session has been declined |
703 progress_id = self.getProgressId(session, content_name) | 703 progress_id = self.get_progress_id(session, content_name) |
704 self.host.bridge.progressError( | 704 self.host.bridge.progress_error( |
705 progress_id, C.PROGRESS_ERROR_DECLINED, client.profile | 705 progress_id, C.PROGRESS_ERROR_DECLINED, client.profile |
706 ) | 706 ) |
707 elif not jingle_elt.success: | 707 elif not jingle_elt.success: |
708 progress_id = self.getProgressId(session, content_name) | 708 progress_id = self.get_progress_id(session, content_name) |
709 first_child = jingle_elt.firstChildElement() | 709 first_child = jingle_elt.firstChildElement() |
710 if first_child is not None: | 710 if first_child is not None: |
711 reason = first_child.name | 711 reason = first_child.name |
712 if jingle_elt.text is not None: | 712 if jingle_elt.text is not None: |
713 reason = f"{reason} - {jingle_elt.text}" | 713 reason = f"{reason} - {jingle_elt.text}" |
714 else: | 714 else: |
715 reason = C.PROGRESS_ERROR_FAILED | 715 reason = C.PROGRESS_ERROR_FAILED |
716 self.host.bridge.progressError( | 716 self.host.bridge.progress_error( |
717 progress_id, reason, client.profile | 717 progress_id, reason, client.profile |
718 ) | 718 ) |
719 | 719 |
720 def _sendCheckSum(self, client, session, content_name, content_data): | 720 def _send_check_sum(self, client, session, content_name, content_data): |
721 """Send the session-info with the hash checksum""" | 721 """Send the session-info with the hash checksum""" |
722 file_data = content_data["application_data"]["file_data"] | 722 file_data = content_data["application_data"]["file_data"] |
723 hasher = file_data["hash_hasher"] | 723 hasher = file_data["hash_hasher"] |
724 hash_ = hasher.hexdigest() | 724 hash_ = hasher.hexdigest() |
725 log.debug("Calculated hash: {}".format(hash_)) | 725 log.debug("Calculated hash: {}".format(hash_)) |
726 iq_elt, jingle_elt = self._j.buildSessionInfo(client, session) | 726 iq_elt, jingle_elt = self._j.build_session_info(client, session) |
727 checksum_elt = jingle_elt.addElement((NS_JINGLE_FT, "checksum")) | 727 checksum_elt = jingle_elt.addElement((NS_JINGLE_FT, "checksum")) |
728 checksum_elt["creator"] = content_data["creator"] | 728 checksum_elt["creator"] = content_data["creator"] |
729 checksum_elt["name"] = content_name | 729 checksum_elt["name"] = content_name |
730 file_elt = checksum_elt.addElement("file") | 730 file_elt = checksum_elt.addElement("file") |
731 file_elt.addChild(self._hash.buildHashElt(hash_)) | 731 file_elt.addChild(self._hash.build_hash_elt(hash_)) |
732 iq_elt.send() | 732 iq_elt.send() |
733 | 733 |
734 def _receiverTryTerminate( | 734 def _receiver_try_terminate( |
735 self, client, session, content_name, content_data, last_try=False | 735 self, client, session, content_name, content_data, last_try=False |
736 ): | 736 ): |
737 """Try to terminate the session | 737 """Try to terminate the session |
738 | 738 |
739 This method must only be used by the receiver. | 739 This method must only be used by the receiver. |
751 log.warning( | 751 log.warning( |
752 "sender didn't sent hash checksum, we can't check the file [{profile}]".format( | 752 "sender didn't sent hash checksum, we can't check the file [{profile}]".format( |
753 profile=client.profile | 753 profile=client.profile |
754 ) | 754 ) |
755 ) | 755 ) |
756 self._j.delayedContentTerminate(client, session, content_name) | 756 self._j.delayed_content_terminate(client, session, content_name) |
757 content_data["stream_object"].close() | 757 content_data["stream_object"].close() |
758 return True | 758 return True |
759 return False | 759 return False |
760 hasher = file_data["hash_hasher"] | 760 hasher = file_data["hash_hasher"] |
761 hash_ = hasher.hexdigest() | 761 hash_ = hasher.hexdigest() |
773 progress_metadata = None | 773 progress_metadata = None |
774 error = "Hash mismatch: given={algo}:{given}, calculated={algo}:{our}".format( | 774 error = "Hash mismatch: given={algo}:{given}, calculated={algo}:{our}".format( |
775 algo=file_data["hash_algo"], given=given_hash, our=hash_ | 775 algo=file_data["hash_algo"], given=given_hash, our=hash_ |
776 ) | 776 ) |
777 | 777 |
778 self._j.delayedContentTerminate(client, session, content_name) | 778 self._j.delayed_content_terminate(client, session, content_name) |
779 content_data["stream_object"].close(progress_metadata, error) | 779 content_data["stream_object"].close(progress_metadata, error) |
780 # we may have the last_try timer still active, so we try to cancel it | 780 # we may have the last_try timer still active, so we try to cancel it |
781 try: | 781 try: |
782 content_data["last_try_timer"].cancel() | 782 content_data["last_try_timer"].cancel() |
783 except (KeyError, internet_error.AlreadyCalled): | 783 except (KeyError, internet_error.AlreadyCalled): |
784 pass | 784 pass |
785 return True | 785 return True |
786 | 786 |
787 def _finishedCb(self, __, client, session, content_name, content_data): | 787 def _finished_cb(self, __, client, session, content_name, content_data): |
788 log.info("File transfer terminated") | 788 log.info("File transfer terminated") |
789 if content_data["senders"] != session["role"]: | 789 if content_data["senders"] != session["role"]: |
790 # we terminate the session only if we are the receiver, | 790 # we terminate the session only if we are the receiver, |
791 # as recommanded in XEP-0234 §2 (after example 6) | 791 # as recommanded in XEP-0234 §2 (after example 6) |
792 content_data["transfer_finished"] = True | 792 content_data["transfer_finished"] = True |
793 if not self._receiverTryTerminate( | 793 if not self._receiver_try_terminate( |
794 client, session, content_name, content_data | 794 client, session, content_name, content_data |
795 ): | 795 ): |
796 # we have not received the hash yet, we wait 5 more seconds | 796 # we have not received the hash yet, we wait 5 more seconds |
797 content_data["last_try_timer"] = reactor.callLater( | 797 content_data["last_try_timer"] = reactor.callLater( |
798 5, | 798 5, |
799 self._receiverTryTerminate, | 799 self._receiver_try_terminate, |
800 client, | 800 client, |
801 session, | 801 session, |
802 content_name, | 802 content_name, |
803 content_data, | 803 content_data, |
804 last_try=True, | 804 last_try=True, |
805 ) | 805 ) |
806 else: | 806 else: |
807 # we are the sender, we send the checksum | 807 # we are the sender, we send the checksum |
808 self._sendCheckSum(client, session, content_name, content_data) | 808 self._send_check_sum(client, session, content_name, content_data) |
809 content_data["stream_object"].close() | 809 content_data["stream_object"].close() |
810 | 810 |
811 def _finishedEb(self, failure, client, session, content_name, content_data): | 811 def _finished_eb(self, failure, client, session, content_name, content_data): |
812 log.warning("Error while streaming file: {}".format(failure)) | 812 log.warning("Error while streaming file: {}".format(failure)) |
813 content_data["stream_object"].close() | 813 content_data["stream_object"].close() |
814 self._j.contentTerminate( | 814 self._j.content_terminate( |
815 client, session, content_name, reason=self._j.REASON_FAILED_TRANSPORT | 815 client, session, content_name, reason=self._j.REASON_FAILED_TRANSPORT |
816 ) | 816 ) |
817 | 817 |
818 | 818 |
819 @implementer(iwokkel.IDisco) | 819 @implementer(iwokkel.IDisco) |