comparison sat/plugins/plugin_xep_0231.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 be6d91572633
children
comparison
equal deleted inserted replaced
4036:c4464d7ae97b 4037:524856bd7b19
56 56
57 class XEP_0231(object): 57 class XEP_0231(object):
58 def __init__(self, host): 58 def __init__(self, host):
59 log.info(_("plugin Bits of Binary initialization")) 59 log.info(_("plugin Bits of Binary initialization"))
60 self.host = host 60 self.host = host
61 host.registerNamespace("bob", NS_BOB) 61 host.register_namespace("bob", NS_BOB)
62 host.trigger.add("xhtml_post_treat", self.XHTMLTrigger) 62 host.trigger.add("xhtml_post_treat", self.xhtml_trigger)
63 host.bridge.addMethod( 63 host.bridge.add_method(
64 "bobGetFile", 64 "bob_get_file",
65 ".plugin", 65 ".plugin",
66 in_sign="sss", 66 in_sign="sss",
67 out_sign="s", 67 out_sign="s",
68 method=self._getFile, 68 method=self._get_file,
69 async_=True, 69 async_=True,
70 ) 70 )
71 71
72 def dumpData(self, cache, data_elt, cid): 72 def dump_data(self, cache, data_elt, cid):
73 """save file encoded in data_elt to cache 73 """save file encoded in data_elt to cache
74 74
75 @param cache(memory.cache.Cache): cache to use to store the data 75 @param cache(memory.cache.Cache): cache to use to store the data
76 @param data_elt(domish.Element): <data> as in XEP-0231 76 @param data_elt(domish.Element): <data> as in XEP-0231
77 @param cid(unicode): content-id 77 @param cid(unicode): content-id
85 raise ValueError 85 raise ValueError
86 except (KeyError, ValueError): 86 except (KeyError, ValueError):
87 log.warning("invalid max-age found") 87 log.warning("invalid max-age found")
88 max_age = None 88 max_age = None
89 89
90 with cache.cacheData( 90 with cache.cache_data(
91 PLUGIN_INFO[C.PI_IMPORT_NAME], cid, data_elt.getAttribute("type"), max_age 91 PLUGIN_INFO[C.PI_IMPORT_NAME], cid, data_elt.getAttribute("type"), max_age
92 ) as f: 92 ) as f:
93 93
94 file_path = Path(f.name) 94 file_path = Path(f.name)
95 f.write(base64.b64decode(str(data_elt))) 95 f.write(base64.b64decode(str(data_elt)))
96 96
97 return file_path 97 return file_path
98 98
99 def getHandler(self, client): 99 def get_handler(self, client):
100 return XEP_0231_handler(self) 100 return XEP_0231_handler(self)
101 101
102 def _requestCb(self, iq_elt, cache, cid): 102 def _request_cb(self, iq_elt, cache, cid):
103 for data_elt in iq_elt.elements(NS_BOB, "data"): 103 for data_elt in iq_elt.elements(NS_BOB, "data"):
104 if data_elt.getAttribute("cid") == cid: 104 if data_elt.getAttribute("cid") == cid:
105 file_path = self.dumpData(cache, data_elt, cid) 105 file_path = self.dump_data(cache, data_elt, cid)
106 return file_path 106 return file_path
107 107
108 log.warning( 108 log.warning(
109 "invalid data stanza received, requested cid was not found:\n{iq_elt}\nrequested cid: {cid}".format( 109 "invalid data stanza received, requested cid was not found:\n{iq_elt}\nrequested cid: {cid}".format(
110 iq_elt=iq_elt, cid=cid 110 iq_elt=iq_elt, cid=cid
111 ) 111 )
112 ) 112 )
113 raise failure.Failure(exceptions.DataError("missing data")) 113 raise failure.Failure(exceptions.DataError("missing data"))
114 114
115 def _requestEb(self, failure_): 115 def _request_eb(self, failure_):
116 """Log the error and continue errback chain""" 116 """Log the error and continue errback chain"""
117 log.warning("Can't get requested data:\n{reason}".format(reason=failure_)) 117 log.warning("Can't get requested data:\n{reason}".format(reason=failure_))
118 return failure_ 118 return failure_
119 119
120 def requestData(self, client, to_jid, cid, cache=None): 120 def request_data(self, client, to_jid, cid, cache=None):
121 """Request data if we don't have it in cache 121 """Request data if we don't have it in cache
122 122
123 @param to_jid(jid.JID): jid to request the data to 123 @param to_jid(jid.JID): jid to request the data to
124 @param cid(unicode): content id 124 @param cid(unicode): content id
125 @param cache(memory.cache.Cache, None): cache to use 125 @param cache(memory.cache.Cache, None): cache to use
131 iq_elt = client.IQ("get") 131 iq_elt = client.IQ("get")
132 iq_elt["to"] = to_jid.full() 132 iq_elt["to"] = to_jid.full()
133 data_elt = iq_elt.addElement((NS_BOB, "data")) 133 data_elt = iq_elt.addElement((NS_BOB, "data"))
134 data_elt["cid"] = cid 134 data_elt["cid"] = cid
135 d = iq_elt.send() 135 d = iq_elt.send()
136 d.addCallback(self._requestCb, cache, cid) 136 d.addCallback(self._request_cb, cache, cid)
137 d.addErrback(self._requestEb) 137 d.addErrback(self._request_eb)
138 return d 138 return d
139 139
140 def _setImgEltSrc(self, path, img_elt): 140 def _set_img_elt_src(self, path, img_elt):
141 img_elt["src"] = "file://{}".format(path) 141 img_elt["src"] = "file://{}".format(path)
142 142
143 def XHTMLTrigger(self, client, message_elt, body_elt, lang, treat_d): 143 def xhtml_trigger(self, client, message_elt, body_elt, lang, treat_d):
144 for img_elt in xml_tools.findAll(body_elt, C.NS_XHTML, "img"): 144 for img_elt in xml_tools.find_all(body_elt, C.NS_XHTML, "img"):
145 source = img_elt.getAttribute("src", "") 145 source = img_elt.getAttribute("src", "")
146 if source.startswith("cid:"): 146 if source.startswith("cid:"):
147 cid = source[4:] 147 cid = source[4:]
148 file_path = client.cache.getFilePath(cid) 148 file_path = client.cache.get_file_path(cid)
149 if file_path is not None: 149 if file_path is not None:
150 #  image is in cache, we change the url 150 #  image is in cache, we change the url
151 img_elt["src"] = "file://{}".format(file_path) 151 img_elt["src"] = "file://{}".format(file_path)
152 continue 152 continue
153 else: 153 else:
154 # image is not in cache, is it given locally? 154 # image is not in cache, is it given locally?
155 for data_elt in message_elt.elements(NS_BOB, "data"): 155 for data_elt in message_elt.elements(NS_BOB, "data"):
156 if data_elt.getAttribute("cid") == cid: 156 if data_elt.getAttribute("cid") == cid:
157 file_path = self.dumpData(client.cache, data_elt, cid) 157 file_path = self.dump_data(client.cache, data_elt, cid)
158 img_elt["src"] = "file://{}".format(file_path) 158 img_elt["src"] = "file://{}".format(file_path)
159 break 159 break
160 else: 160 else:
161 # cid not found locally, we need to request it 161 # cid not found locally, we need to request it
162 # so we use the deferred 162 # so we use the deferred
163 d = self.requestData(client, jid.JID(message_elt["from"]), cid) 163 d = self.request_data(client, jid.JID(message_elt["from"]), cid)
164 d.addCallback(partial(self._setImgEltSrc, img_elt=img_elt)) 164 d.addCallback(partial(self._set_img_elt_src, img_elt=img_elt))
165 treat_d.addCallback(lambda __: d) 165 treat_d.addCallback(lambda __: d)
166 166
167 def onComponentRequest(self, iq_elt, client): 167 def on_component_request(self, iq_elt, client):
168 """cache data is retrieve from common cache for components""" 168 """cache data is retrieve from common cache for components"""
169 # FIXME: this is a security/privacy issue as no access check is done 169 # FIXME: this is a security/privacy issue as no access check is done
170 # but this is mitigated by the fact that the cid must be known. 170 # but this is mitigated by the fact that the cid must be known.
171 # An access check should be implemented though. 171 # An access check should be implemented though.
172 172
177 except KeyError: 177 except KeyError:
178 error_elt = jabber_error.StanzaError("not-acceptable").toResponse(iq_elt) 178 error_elt = jabber_error.StanzaError("not-acceptable").toResponse(iq_elt)
179 client.send(error_elt) 179 client.send(error_elt)
180 return 180 return
181 181
182 metadata = self.host.common_cache.getMetadata(cid) 182 metadata = self.host.common_cache.get_metadata(cid)
183 if metadata is None: 183 if metadata is None:
184 error_elt = jabber_error.StanzaError("item-not-found").toResponse(iq_elt) 184 error_elt = jabber_error.StanzaError("item-not-found").toResponse(iq_elt)
185 client.send(error_elt) 185 client.send(error_elt)
186 return 186 return
187 187
194 data_elt["cid"] = cid 194 data_elt["cid"] = cid
195 data_elt["type"] = metadata["mime_type"] 195 data_elt["type"] = metadata["mime_type"]
196 data_elt["max-age"] = str(int(max(0, metadata["eol"] - time.time()))) 196 data_elt["max-age"] = str(int(max(0, metadata["eol"] - time.time())))
197 client.send(result_elt) 197 client.send(result_elt)
198 198
199 def _getFile(self, peer_jid_s, cid, profile): 199 def _get_file(self, peer_jid_s, cid, profile):
200 peer_jid = jid.JID(peer_jid_s) 200 peer_jid = jid.JID(peer_jid_s)
201 assert cid 201 assert cid
202 client = self.host.getClient(profile) 202 client = self.host.get_client(profile)
203 d = self.getFile(client, peer_jid, cid) 203 d = self.get_file(client, peer_jid, cid)
204 d.addCallback(lambda path: str(path)) 204 d.addCallback(lambda path: str(path))
205 return d 205 return d
206 206
207 def getFile(self, client, peer_jid, cid, parent_elt=None): 207 def get_file(self, client, peer_jid, cid, parent_elt=None):
208 """Retrieve a file from it's content-id 208 """Retrieve a file from it's content-id
209 209
210 @param peer_jid(jid.JID): jid of the entity offering the data 210 @param peer_jid(jid.JID): jid of the entity offering the data
211 @param cid(unicode): content-id of file data 211 @param cid(unicode): content-id of file data
212 @param parent_elt(domish.Element, None): if file is not in cache, 212 @param parent_elt(domish.Element, None): if file is not in cache,
213 data will be looked after in children of this elements. 213 data will be looked after in children of this elements.
214 None to ignore 214 None to ignore
215 @return D(Path): path to cached data 215 @return D(Path): path to cached data
216 """ 216 """
217 file_path = client.cache.getFilePath(cid) 217 file_path = client.cache.get_file_path(cid)
218 if file_path is not None: 218 if file_path is not None:
219 #  file is in cache 219 #  file is in cache
220 return defer.succeed(file_path) 220 return defer.succeed(file_path)
221 else: 221 else:
222 # file not in cache, is it given locally? 222 # file not in cache, is it given locally?
223 if parent_elt is not None: 223 if parent_elt is not None:
224 for data_elt in parent_elt.elements(NS_BOB, "data"): 224 for data_elt in parent_elt.elements(NS_BOB, "data"):
225 if data_elt.getAttribute("cid") == cid: 225 if data_elt.getAttribute("cid") == cid:
226 return defer.succeed(self.dumpData(client.cache, data_elt, cid)) 226 return defer.succeed(self.dump_data(client.cache, data_elt, cid))
227 227
228 # cid not found locally, we need to request it 228 # cid not found locally, we need to request it
229 # so we use the deferred 229 # so we use the deferred
230 return self.requestData(client, peer_jid, cid) 230 return self.request_data(client, peer_jid, cid)
231 231
232 232
233 @implementer(iwokkel.IDisco) 233 @implementer(iwokkel.IDisco)
234 class XEP_0231_handler(xmlstream.XMPPHandler): 234 class XEP_0231_handler(xmlstream.XMPPHandler):
235 235
238 self.host = plugin_parent.host 238 self.host = plugin_parent.host
239 239
240 def connectionInitialized(self): 240 def connectionInitialized(self):
241 if self.parent.is_component: 241 if self.parent.is_component:
242 self.xmlstream.addObserver( 242 self.xmlstream.addObserver(
243 IQ_BOB_REQUEST, self.plugin_parent.onComponentRequest, client=self.parent 243 IQ_BOB_REQUEST, self.plugin_parent.on_component_request, client=self.parent
244 ) 244 )
245 245
246 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): 246 def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
247 return [disco.DiscoFeature(NS_BOB)] 247 return [disco.DiscoFeature(NS_BOB)]
248 248