comparison sat/plugins/plugin_xep_0363.py @ 3526:e84ffb48acd4

plugin XEP-0363: allow async callbacks in handlers + method to generate `file-too-large` element
author Goffi <goffi@goffi.org>
date Wed, 05 May 2021 15:37:33 +0200
parents be6d91572633
children 0ff265725489
comparison
equal deleted inserted replaced
3525:7f5bf108961a 3526:e84ffb48acd4
22 from dataclasses import dataclass 22 from dataclasses import dataclass
23 from urllib import parse 23 from urllib import parse
24 from wokkel import disco, iwokkel 24 from wokkel import disco, iwokkel
25 from zope.interface import implementer 25 from zope.interface import implementer
26 from twisted.words.protocols.jabber import jid, xmlstream, error 26 from twisted.words.protocols.jabber import jid, xmlstream, error
27 from twisted.words.xish import domish
27 from twisted.internet import reactor 28 from twisted.internet import reactor
28 from twisted.internet import defer 29 from twisted.internet import defer
29 from twisted.web import client as http_client 30 from twisted.web import client as http_client
30 from twisted.web import http_headers 31 from twisted.web import http_headers
31 from sat.core.i18n import _ 32 from sat.core.i18n import _
32 from sat.core.xmpp import SatXMPPComponent 33 from sat.core.xmpp import SatXMPPComponent
33 from sat.core.constants import Const as C 34 from sat.core.constants import Const as C
34 from sat.core.log import getLogger 35 from sat.core.log import getLogger
35 from sat.core import exceptions 36 from sat.core import exceptions
36 from sat.tools import web as sat_web 37 from sat.tools import web as sat_web, utils
37 38
38 39
39 log = getLogger(__name__) 40 log = getLogger(__name__)
40 41
41 PLUGIN_INFO = { 42 PLUGIN_INFO = {
120 assert callback not in self.handlers 121 assert callback not in self.handlers
121 req_handler = RequestHandler(callback, priority) 122 req_handler = RequestHandler(callback, priority)
122 self.handlers.append(req_handler) 123 self.handlers.append(req_handler)
123 self.handlers.sort(key=lambda handler: handler.priority, reverse=True) 124 self.handlers.sort(key=lambda handler: handler.priority, reverse=True)
124 125
126 def getFileTooLargeElt(self, max_size: int) -> domish.Element:
127 """Generate <file-too-large> app condition for errors"""
128 file_too_large_elt = domish.Element((NS_HTTP_UPLOAD, "file-too-large"))
129 file_too_large_elt.addElement("max-file-size", str(max_size))
130 return file_too_large_elt
131
125 async def getHTTPUploadEntity(self, client, upload_jid=None): 132 async def getHTTPUploadEntity(self, client, upload_jid=None):
126 """Get HTTP upload capable entity 133 """Get HTTP upload capable entity
127 134
128 upload_jid is checked, then its components 135 upload_jid is checked, then its components
129 @param upload_jid(None, jid.JID): entity to check 136 @param upload_jid(None, jid.JID): entity to check
354 361
355 # component 362 # component
356 363
357 def onComponentRequest(self, iq_elt, client): 364 def onComponentRequest(self, iq_elt, client):
358 iq_elt.handled=True 365 iq_elt.handled=True
366 defer.ensureDeferred(self.handleComponentRequest(client, iq_elt))
367
368 async def handleComponentRequest(self, client, iq_elt):
359 try: 369 try:
360 request_elt = next(iq_elt.elements(NS_HTTP_UPLOAD, "request")) 370 request_elt = next(iq_elt.elements(NS_HTTP_UPLOAD, "request"))
361 request = UploadRequest( 371 request = UploadRequest(
362 from_=jid.JID(iq_elt['from']), 372 from_=jid.JID(iq_elt['from']),
363 filename=parse.quote(request_elt['filename'].replace('/', '_'), safe=''), 373 filename=parse.quote(request_elt['filename'].replace('/', '_'), safe=''),
370 380
371 err = None 381 err = None
372 382
373 for handler in self.handlers: 383 for handler in self.handlers:
374 try: 384 try:
375 slot = handler.callback(client, request) 385 slot = await utils.asDeferred(handler.callback, client, request)
376 except error.StanzaError as e: 386 except error.StanzaError as e:
377 log.warning( 387 log.warning(
378 "a stanza error has been raised while processing HTTP Upload of " 388 "a stanza error has been raised while processing HTTP Upload of "
379 f"request: {e}" 389 f"request: {e}"
380 ) 390 )
387 break 397 break
388 else: 398 else:
389 log.warning( 399 log.warning(
390 _("no service can handle HTTP Upload request: {elt}") 400 _("no service can handle HTTP Upload request: {elt}")
391 .format(elt=iq_elt.toXml())) 401 .format(elt=iq_elt.toXml()))
392 if err is not None: 402 if err is None:
393 condition = err.condition 403 err = error.StanzaError("feature-not-implemented")
394 else: 404 client.send(err.toResponse(iq_elt))
395 condition = "feature-not-implemented"
396 client.sendError(iq_elt, condition)
397 return 405 return
398 406
399 iq_result_elt = xmlstream.toResponse(iq_elt, "result") 407 iq_result_elt = xmlstream.toResponse(iq_elt, "result")
400 slot_elt = iq_result_elt.addElement((NS_HTTP_UPLOAD, 'slot')) 408 slot_elt = iq_result_elt.addElement((NS_HTTP_UPLOAD, 'slot'))
401 put_elt = slot_elt.addElement('put') 409 put_elt = slot_elt.addElement('put')