Mercurial > libervia-backend
comparison src/plugins/plugin_xep_0231.py @ 2511:20a5e7db0609
plugin XEP-0231: separated the requestData code in a method which can called independantly + some minor improvments
author | Goffi <goffi@goffi.org> |
---|---|
date | Fri, 02 Mar 2018 17:45:23 +0100 |
parents | 0046283a285d |
children | 95c31756944c |
comparison
equal
deleted
inserted
replaced
2510:4001aa395a04 | 2511:20a5e7db0609 |
---|---|
17 # You should have received a copy of the GNU Affero General Public License | 17 # You should have received a copy of the GNU Affero General Public License |
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 import exceptions | |
22 from sat.core.log import getLogger | 23 from sat.core.log import getLogger |
23 log = getLogger(__name__) | 24 log = getLogger(__name__) |
24 from sat.tools import xml_tools | 25 from sat.tools import xml_tools |
25 from wokkel import disco, iwokkel | 26 from wokkel import disco, iwokkel |
26 from zope.interface import implements | 27 from zope.interface import implements |
27 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | 28 from twisted.python import failure |
29 from twisted.words.protocols.jabber import xmlstream | |
30 from twisted.words.protocols.jabber import jid | |
31 from functools import partial | |
28 import base64 | 32 import base64 |
29 | 33 |
30 | 34 |
31 PLUGIN_INFO = { | 35 PLUGIN_INFO = { |
32 C.PI_NAME: "Bits of Binary", | 36 C.PI_NAME: "Bits of Binary", |
47 def __init__(self, host): | 51 def __init__(self, host): |
48 log.info(_(u"plugin Bits of Binary initialization")) | 52 log.info(_(u"plugin Bits of Binary initialization")) |
49 self.host = host | 53 self.host = host |
50 host.trigger.add("xhtml_post_treat", self.XHTMLTrigger) | 54 host.trigger.add("xhtml_post_treat", self.XHTMLTrigger) |
51 | 55 |
52 def dumpData(self, client, data_elt, cid): | 56 def dumpData(self, cache, data_elt, cid): |
53 """save file encoded in data_elt to cache | 57 """save file encoded in data_elt to cache |
54 | 58 |
59 @param cache(memory.cache.Cache): cache to use to store the data | |
55 @param data_elt(domish.Element): <data> as in XEP-0231 | 60 @param data_elt(domish.Element): <data> as in XEP-0231 |
56 @param cid(unicode): content-id | 61 @param cid(unicode): content-id |
57 @return(unicode): full path to dumped file | 62 @return(unicode): full path to dumped file |
58 """ | 63 """ |
59 # FIXME: is it needed to use a separate thread? | 64 # FIXME: is it needed to use a separate thread? |
60 # probably not with the little data expected with BoB | 65 # probably not with the little data expected with BoB |
61 mime_type = data_elt.getAttribute('type','') | |
62 | |
63 try: | 66 try: |
64 max_age = int(data_elt['max-age']) | 67 max_age = int(data_elt['max-age']) |
68 if max_age < 0: | |
69 raise ValueError | |
65 except (KeyError, ValueError): | 70 except (KeyError, ValueError): |
66 log.warning(u'invalid max-age found') | 71 log.warning(u'invalid max-age found') |
67 max_age = None | 72 max_age = None |
68 | 73 |
69 with client.cache.cacheData( | 74 with cache.cacheData( |
70 PLUGIN_INFO['import_name'], | 75 PLUGIN_INFO[C.PI_IMPORT_NAME], |
71 cid, | 76 cid, |
72 mime_type, | 77 data_elt.getAttribute('type'), |
73 max_age) as f: | 78 max_age) as f: |
74 | 79 |
75 file_path = f.name | 80 file_path = f.name |
76 f.write(base64.b64decode(str(data_elt))) | 81 f.write(base64.b64decode(str(data_elt))) |
77 | 82 |
78 return file_path | 83 return file_path |
79 | 84 |
80 def getHandler(self, client): | 85 def getHandler(self, client): |
81 return XEP_0231_handler() | 86 return XEP_0231_handler() |
82 | 87 |
83 def _dataCb(self, iq_elt, client, img_elt, cid): | 88 def _requestCb(self, iq_elt, cache, cid): |
84 for data_elt in iq_elt.elements(NS_BOB, u'data'): | 89 for data_elt in iq_elt.elements(NS_BOB, u'data'): |
85 if data_elt.getAttribute('cid') == cid: | 90 if data_elt.getAttribute('cid') == cid: |
86 file_path = self.dumpData(client, data_elt, cid) | 91 file_path = self.dumpData(cache, data_elt, cid) |
87 img_elt[u'src'] = u'file://{}'.format(file_path) | 92 return file_path |
88 break | |
89 else: | |
90 log.warning(u"invalid data stanza received, requested cid was not found:\n{iq_elt}\nrequested cid: {cid}".format( | |
91 iq_elt = iq_elt, | |
92 cid = cid | |
93 )) | |
94 | 93 |
95 def _dataEb(self, iq_elt): | 94 log.warning(u"invalid data stanza received, requested cid was not found:\n{iq_elt}\nrequested cid: {cid}".format( |
96 log.warning(u"Can't get requested data:\n{iq_elt}".format(iq_elt=iq_elt)) | 95 iq_elt = iq_elt, |
96 cid = cid | |
97 )) | |
98 raise failure.Failure(exceptions.DataError("missing data")) | |
99 | |
100 def _requestEb(self, failure_): | |
101 """Log the error and continue errback chain""" | |
102 log.warning(u"Can't get requested data:\n{reason}".format(reason=failure_)) | |
103 return failure_ | |
104 | |
105 def requestData(self, client, to_jid, cid, cache=None): | |
106 """Request data if we don't have it in cache | |
107 | |
108 @param to_jid(jid.JID): jid to request the data to | |
109 @param cid(unicode): content id | |
110 @param cache(memory.cache.Cache, None): cache to use | |
111 client.cache will be used if None | |
112 """ | |
113 if cache is None: | |
114 cache = client.cache | |
115 iq_elt = client.IQ('get') | |
116 iq_elt['to'] = to_jid.full() | |
117 data_elt = iq_elt.addElement((NS_BOB, 'data')) | |
118 data_elt['cid'] = cid | |
119 d = iq_elt.send() | |
120 d.addCallback(self._requestCb, cache, cid) | |
121 d.addErrback(self._requestEb) | |
122 | |
123 def _setImgEltSrc(self, path, img_elt): | |
124 img_elt[u'src'] = u'file://{}'.format(path) | |
97 | 125 |
98 def XHTMLTrigger(self, client, message_elt, body_elt, lang, treat_d): | 126 def XHTMLTrigger(self, client, message_elt, body_elt, lang, treat_d): |
99 for img_elt in xml_tools.findAll(body_elt, C.NS_XHTML, u'img'): | 127 for img_elt in xml_tools.findAll(body_elt, C.NS_XHTML, u'img'): |
100 source = img_elt.getAttribute(u'src','') | 128 source = img_elt.getAttribute(u'src','') |
101 if source.startswith(u'cid:'): | 129 if source.startswith(u'cid:'): |
107 continue | 135 continue |
108 else: | 136 else: |
109 # image is not in cache, is it given locally? | 137 # image is not in cache, is it given locally? |
110 for data_elt in message_elt.elements(NS_BOB, u'data'): | 138 for data_elt in message_elt.elements(NS_BOB, u'data'): |
111 if data_elt.getAttribute('cid') == cid: | 139 if data_elt.getAttribute('cid') == cid: |
112 file_path = self.dumpData(data_elt, cid) | 140 file_path = self.dumpData(client.cache, data_elt, cid) |
113 img_elt[u'src'] = u'file://{}'.format(file_path) | 141 img_elt[u'src'] = u'file://{}'.format(file_path) |
114 break | 142 break |
115 else: | 143 else: |
116 # cid not found locally, we need to request it | 144 # cid not found locally, we need to request it |
117 # so we use the deferred | 145 # so we use the deferred |
118 iq_elt = client.IQ('get') | 146 d = self.requestData(client, jid.JID(message_elt['from']), cid) |
119 iq_elt['to'] = message_elt['from'] | 147 d.addCallback(partial(self._setImgEltSrc, img_elt=img_elt)) |
120 data_elt = iq_elt.addElement((NS_BOB, 'data')) | |
121 data_elt['cid'] = cid | |
122 d = iq_elt.send() | |
123 d.addCallback(self._dataCb, client, img_elt, cid) | |
124 d.addErrback(self._dataEb) | |
125 treat_d.addCallback(lambda dummy: d) | 148 treat_d.addCallback(lambda dummy: d) |
126 | 149 |
127 | 150 |
128 class XEP_0231_handler(XMPPHandler): | 151 class XEP_0231_handler(xmlstream.XMPPHandler): |
129 implements(iwokkel.IDisco) | 152 implements(iwokkel.IDisco) |
130 | 153 |
131 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | 154 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): |
132 return [disco.DiscoFeature(NS_BOB)] | 155 return [disco.DiscoFeature(NS_BOB)] |
133 | 156 |