Mercurial > libervia-backend
comparison sat/plugins/plugin_xep_0363.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 | 412b99c29d83 |
children |
comparison
equal
deleted
inserted
replaced
4036:c4464d7ae97b | 4037:524856bd7b19 |
---|---|
84 Slot=Slot | 84 Slot=Slot |
85 | 85 |
86 def __init__(self, host): | 86 def __init__(self, host): |
87 log.info(_("plugin HTTP File Upload initialization")) | 87 log.info(_("plugin HTTP File Upload initialization")) |
88 self.host = host | 88 self.host = host |
89 host.bridge.addMethod( | 89 host.bridge.add_method( |
90 "fileHTTPUpload", | 90 "file_http_upload", |
91 ".plugin", | 91 ".plugin", |
92 in_sign="sssbs", | 92 in_sign="sssbs", |
93 out_sign="", | 93 out_sign="", |
94 method=self._file_http_upload, | 94 method=self._file_http_upload, |
95 ) | 95 ) |
96 host.bridge.addMethod( | 96 host.bridge.add_method( |
97 "fileHTTPUploadGetSlot", | 97 "file_http_upload_get_slot", |
98 ".plugin", | 98 ".plugin", |
99 in_sign="sisss", | 99 in_sign="sisss", |
100 out_sign="(ssaa{ss})", | 100 out_sign="(ssaa{ss})", |
101 method=self._getSlot, | 101 method=self._get_slot, |
102 async_=True, | 102 async_=True, |
103 ) | 103 ) |
104 host.plugins["UPLOAD"].register( | 104 host.plugins["UPLOAD"].register( |
105 "HTTP Upload", self.getHTTPUploadEntity, self.file_http_upload | 105 "HTTP Upload", self.get_http_upload_entity, self.file_http_upload |
106 ) | 106 ) |
107 # list of callbacks used when a request is done to a component | 107 # list of callbacks used when a request is done to a component |
108 self.handlers = [] | 108 self.handlers = [] |
109 # XXX: there is not yet official short name, so we use "http_upload" | 109 # XXX: there is not yet official short name, so we use "http_upload" |
110 host.registerNamespace("http_upload", NS_HTTP_UPLOAD) | 110 host.register_namespace("http_upload", NS_HTTP_UPLOAD) |
111 | 111 |
112 def getHandler(self, client): | 112 def get_handler(self, client): |
113 return XEP_0363_handler(self) | 113 return XEP_0363_handler(self) |
114 | 114 |
115 def registerHandler(self, callback, priority=0): | 115 def register_handler(self, callback, priority=0): |
116 """Register a request handler | 116 """Register a request handler |
117 | 117 |
118 @param callack: method to call when a request is done | 118 @param callack: method to call when a request is done |
119 the callback must return a Slot if the request is handled, | 119 the callback must return a Slot if the request is handled, |
120 otherwise, other callbacks will be tried. | 120 otherwise, other callbacks will be tried. |
125 assert callback not in self.handlers | 125 assert callback not in self.handlers |
126 req_handler = RequestHandler(callback, priority) | 126 req_handler = RequestHandler(callback, priority) |
127 self.handlers.append(req_handler) | 127 self.handlers.append(req_handler) |
128 self.handlers.sort(key=lambda handler: handler.priority, reverse=True) | 128 self.handlers.sort(key=lambda handler: handler.priority, reverse=True) |
129 | 129 |
130 def getFileTooLargeElt(self, max_size: int) -> domish.Element: | 130 def get_file_too_large_elt(self, max_size: int) -> domish.Element: |
131 """Generate <file-too-large> app condition for errors""" | 131 """Generate <file-too-large> app condition for errors""" |
132 file_too_large_elt = domish.Element((NS_HTTP_UPLOAD, "file-too-large")) | 132 file_too_large_elt = domish.Element((NS_HTTP_UPLOAD, "file-too-large")) |
133 file_too_large_elt.addElement("max-file-size", str(max_size)) | 133 file_too_large_elt.addElement("max-file-size", str(max_size)) |
134 return file_too_large_elt | 134 return file_too_large_elt |
135 | 135 |
136 async def getHTTPUploadEntity(self, client, upload_jid=None): | 136 async def get_http_upload_entity(self, client, upload_jid=None): |
137 """Get HTTP upload capable entity | 137 """Get HTTP upload capable entity |
138 | 138 |
139 upload_jid is checked, then its components | 139 upload_jid is checked, then its components |
140 @param upload_jid(None, jid.JID): entity to check | 140 @param upload_jid(None, jid.JID): entity to check |
141 @return(D(jid.JID)): first HTTP upload capable entity | 141 @return(D(jid.JID)): first HTTP upload capable entity |
142 @raise exceptions.NotFound: no entity found | 142 @raise exceptions.NotFound: no entity found |
143 """ | 143 """ |
144 try: | 144 try: |
145 entity = client.http_upload_service | 145 entity = client.http_upload_service |
146 except AttributeError: | 146 except AttributeError: |
147 found_entities = await self.host.findFeaturesSet(client, (NS_HTTP_UPLOAD,)) | 147 found_entities = await self.host.find_features_set(client, (NS_HTTP_UPLOAD,)) |
148 try: | 148 try: |
149 entity = client.http_upload_service = next(iter(found_entities)) | 149 entity = client.http_upload_service = next(iter(found_entities)) |
150 except StopIteration: | 150 except StopIteration: |
151 entity = client.http_upload_service = None | 151 entity = client.http_upload_service = None |
152 | 152 |
156 return entity | 156 return entity |
157 | 157 |
158 def _file_http_upload(self, filepath, filename="", upload_jid="", | 158 def _file_http_upload(self, filepath, filename="", upload_jid="", |
159 ignore_tls_errors=False, profile=C.PROF_KEY_NONE): | 159 ignore_tls_errors=False, profile=C.PROF_KEY_NONE): |
160 assert os.path.isabs(filepath) and os.path.isfile(filepath) | 160 assert os.path.isabs(filepath) and os.path.isfile(filepath) |
161 client = self.host.getClient(profile) | 161 client = self.host.get_client(profile) |
162 return defer.ensureDeferred(self.file_http_upload( | 162 return defer.ensureDeferred(self.file_http_upload( |
163 client, | 163 client, |
164 filepath, | 164 filepath, |
165 filename or None, | 165 filename or None, |
166 jid.JID(upload_jid) if upload_jid else None, | 166 jid.JID(upload_jid) if upload_jid else None, |
202 self.host.trigger.point( | 202 self.host.trigger.point( |
203 "XEP-0363_upload_pre_slot", client, extra, file_metadata, | 203 "XEP-0363_upload_pre_slot", client, extra, file_metadata, |
204 triggers_no_cancel=True | 204 triggers_no_cancel=True |
205 ) | 205 ) |
206 try: | 206 try: |
207 slot = await self.getSlot( | 207 slot = await self.get_slot( |
208 client, file_metadata["filename"], file_metadata["size"], | 208 client, file_metadata["filename"], file_metadata["size"], |
209 upload_jid=upload_jid | 209 upload_jid=upload_jid |
210 ) | 210 ) |
211 except Exception as e: | 211 except Exception as e: |
212 log.warning(_("Can't get upload slot: {reason}").format(reason=e)) | 212 log.warning(_("Can't get upload slot: {reason}").format(reason=e)) |
233 name = name.encode('utf-8') | 233 name = name.encode('utf-8') |
234 value = value.encode('utf-8') | 234 value = value.encode('utf-8') |
235 headers[name] = value | 235 headers[name] = value |
236 | 236 |
237 | 237 |
238 await self.host.trigger.asyncPoint( | 238 await self.host.trigger.async_point( |
239 "XEP-0363_upload", client, extra, sat_file, file_producer, slot, | 239 "XEP-0363_upload", client, extra, sat_file, file_producer, slot, |
240 triggers_no_cancel=True) | 240 triggers_no_cancel=True) |
241 | 241 |
242 download_d = agent.request( | 242 download_d = agent.request( |
243 b"PUT", | 243 b"PUT", |
257 | 257 |
258 def _upload_cb(self, __, sat_file, slot): | 258 def _upload_cb(self, __, sat_file, slot): |
259 """Called once file is successfully uploaded | 259 """Called once file is successfully uploaded |
260 | 260 |
261 @param sat_file(SatFile): file used for the upload | 261 @param sat_file(SatFile): file used for the upload |
262 should be closed, but it is needed to send the progressFinished signal | 262 should be closed, but it is needed to send the progress_finished signal |
263 @param slot(Slot): put/get urls | 263 @param slot(Slot): put/get urls |
264 """ | 264 """ |
265 log.info(f"HTTP upload finished ({slot.get})") | 265 log.info(f"HTTP upload finished ({slot.get})") |
266 sat_file.progressFinished({"url": slot.get}) | 266 sat_file.progress_finished({"url": slot.get}) |
267 return slot.get | 267 return slot.get |
268 | 268 |
269 def _upload_eb(self, failure_, sat_file): | 269 def _upload_eb(self, failure_, sat_file): |
270 """Called on unsuccessful upload | 270 """Called on unsuccessful upload |
271 | 271 |
272 @param sat_file(SatFile): file used for the upload | 272 @param sat_file(SatFile): file used for the upload |
273 should be closed, be is needed to send the progressError signal | 273 should be closed, be is needed to send the progress_error signal |
274 """ | 274 """ |
275 try: | 275 try: |
276 wrapped_fail = failure_.value.reasons[0] | 276 wrapped_fail = failure_.value.reasons[0] |
277 except (AttributeError, IndexError) as e: | 277 except (AttributeError, IndexError) as e: |
278 log.warning(_("upload failed: {reason}").format(reason=e)) | 278 log.warning(_("upload failed: {reason}").format(reason=e)) |
279 sat_file.progressError(str(failure_)) | 279 sat_file.progress_error(str(failure_)) |
280 else: | 280 else: |
281 if wrapped_fail.check(sat_web.SSLError): | 281 if wrapped_fail.check(sat_web.SSLError): |
282 msg = "TLS validation error, can't connect to HTTPS server" | 282 msg = "TLS validation error, can't connect to HTTPS server" |
283 else: | 283 else: |
284 msg = "can't upload file" | 284 msg = "can't upload file" |
285 log.warning(msg + ": " + str(wrapped_fail.value)) | 285 log.warning(msg + ": " + str(wrapped_fail.value)) |
286 sat_file.progressError(msg) | 286 sat_file.progress_error(msg) |
287 raise failure_ | 287 raise failure_ |
288 | 288 |
289 def _getSlot(self, filename, size, content_type, upload_jid, | 289 def _get_slot(self, filename, size, content_type, upload_jid, |
290 profile_key=C.PROF_KEY_NONE): | 290 profile_key=C.PROF_KEY_NONE): |
291 """Get an upload slot | 291 """Get an upload slot |
292 | 292 |
293 This method can be used when uploading is done by the frontend | 293 This method can be used when uploading is done by the frontend |
294 @param filename(unicode): name of the file to upload | 294 @param filename(unicode): name of the file to upload |
295 @param size(int): size of the file (must be non null) | 295 @param size(int): size of the file (must be non null) |
296 @param upload_jid(str, ''): HTTP upload capable entity | 296 @param upload_jid(str, ''): HTTP upload capable entity |
297 @param content_type(unicode, None): MIME type of the content | 297 @param content_type(unicode, None): MIME type of the content |
298 empty string or None to guess automatically | 298 empty string or None to guess automatically |
299 """ | 299 """ |
300 client = self.host.getClient(profile_key) | 300 client = self.host.get_client(profile_key) |
301 filename = filename.replace("/", "_") | 301 filename = filename.replace("/", "_") |
302 d = defer.ensureDeferred(self.getSlot( | 302 d = defer.ensureDeferred(self.get_slot( |
303 client, filename, size, content_type or None, jid.JID(upload_jid) or None | 303 client, filename, size, content_type or None, jid.JID(upload_jid) or None |
304 )) | 304 )) |
305 d.addCallback(lambda slot: (slot.get, slot.put, slot.headers)) | 305 d.addCallback(lambda slot: (slot.get, slot.put, slot.headers)) |
306 return d | 306 return d |
307 | 307 |
308 async def getSlot(self, client, filename, size, content_type=None, upload_jid=None): | 308 async def get_slot(self, client, filename, size, content_type=None, upload_jid=None): |
309 """Get a slot (i.e. download/upload links) | 309 """Get a slot (i.e. download/upload links) |
310 | 310 |
311 @param filename(unicode): name to use for the upload | 311 @param filename(unicode): name to use for the upload |
312 @param size(int): size of the file to upload (must be >0) | 312 @param size(int): size of the file to upload (must be >0) |
313 @param content_type(None, unicode): MIME type of the content | 313 @param content_type(None, unicode): MIME type of the content |
325 | 325 |
326 if upload_jid is None: | 326 if upload_jid is None: |
327 try: | 327 try: |
328 upload_jid = client.http_upload_service | 328 upload_jid = client.http_upload_service |
329 except AttributeError: | 329 except AttributeError: |
330 found_entity = await self.getHTTPUploadEntity(client) | 330 found_entity = await self.get_http_upload_entity(client) |
331 return await self.getSlot( | 331 return await self.get_slot( |
332 client, filename, size, content_type, found_entity) | 332 client, filename, size, content_type, found_entity) |
333 else: | 333 else: |
334 if upload_jid is None: | 334 if upload_jid is None: |
335 raise exceptions.NotFound("No HTTP upload entity found") | 335 raise exceptions.NotFound("No HTTP upload entity found") |
336 | 336 |
372 | 372 |
373 return Slot(put=put_url, get=get_url, headers=headers) | 373 return Slot(put=put_url, get=get_url, headers=headers) |
374 | 374 |
375 # component | 375 # component |
376 | 376 |
377 def onComponentRequest(self, iq_elt, client): | 377 def on_component_request(self, iq_elt, client): |
378 iq_elt.handled=True | 378 iq_elt.handled=True |
379 defer.ensureDeferred(self.handleComponentRequest(client, iq_elt)) | 379 defer.ensureDeferred(self.handle_component_request(client, iq_elt)) |
380 | 380 |
381 async def handleComponentRequest(self, client, iq_elt): | 381 async def handle_component_request(self, client, iq_elt): |
382 try: | 382 try: |
383 request_elt = next(iq_elt.elements(NS_HTTP_UPLOAD, "request")) | 383 request_elt = next(iq_elt.elements(NS_HTTP_UPLOAD, "request")) |
384 request = UploadRequest( | 384 request = UploadRequest( |
385 from_=jid.JID(iq_elt['from']), | 385 from_=jid.JID(iq_elt['from']), |
386 filename=parse.quote(request_elt['filename'].replace('/', '_'), safe=''), | 386 filename=parse.quote(request_elt['filename'].replace('/', '_'), safe=''), |
393 | 393 |
394 err = None | 394 err = None |
395 | 395 |
396 for handler in self.handlers: | 396 for handler in self.handlers: |
397 try: | 397 try: |
398 slot = await utils.asDeferred(handler.callback, client, request) | 398 slot = await utils.as_deferred(handler.callback, client, request) |
399 except error.StanzaError as e: | 399 except error.StanzaError as e: |
400 log.warning( | 400 log.warning( |
401 "a stanza error has been raised while processing HTTP Upload of " | 401 "a stanza error has been raised while processing HTTP Upload of " |
402 f"request: {e}" | 402 f"request: {e}" |
403 ) | 403 ) |
434 | 434 |
435 def connectionInitialized(self): | 435 def connectionInitialized(self): |
436 if ((self.parent.is_component | 436 if ((self.parent.is_component |
437 and PLUGIN_INFO[C.PI_IMPORT_NAME] in self.parent.enabled_features)): | 437 and PLUGIN_INFO[C.PI_IMPORT_NAME] in self.parent.enabled_features)): |
438 self.xmlstream.addObserver( | 438 self.xmlstream.addObserver( |
439 IQ_HTTP_UPLOAD_REQUEST, self.plugin_parent.onComponentRequest, | 439 IQ_HTTP_UPLOAD_REQUEST, self.plugin_parent.on_component_request, |
440 client=self.parent | 440 client=self.parent |
441 ) | 441 ) |
442 | 442 |
443 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): | 443 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): |
444 if ((self.parent.is_component | 444 if ((self.parent.is_component |