comparison sat/plugins/plugin_xep_0264.py @ 3028:ab2696e34d29

Python 3 port: /!\ this is a huge commit /!\ starting from this commit, SàT is needs Python 3.6+ /!\ SàT maybe be instable or some feature may not work anymore, this will improve with time This patch port backend, bridge and frontends to Python 3. Roughly this has been done this way: - 2to3 tools has been applied (with python 3.7) - all references to python2 have been replaced with python3 (notably shebangs) - fixed files not handled by 2to3 (notably the shell script) - several manual fixes - fixed issues reported by Python 3 that where not handled in Python 2 - replaced "async" with "async_" when needed (it's a reserved word from Python 3.7) - replaced zope's "implements" with @implementer decorator - temporary hack to handle data pickled in database, as str or bytes may be returned, to be checked later - fixed hash comparison for password - removed some code which is not needed anymore with Python 3 - deactivated some code which needs to be checked (notably certificate validation) - tested with jp, fixed reported issues until some basic commands worked - ported Primitivus (after porting dependencies like urwid satext) - more manual fixes
author Goffi <goffi@goffi.org>
date Tue, 13 Aug 2019 19:08:41 +0200
parents 003b8b4b56a7
children 9d0df638c8b4
comparison
equal deleted inserted replaced
3027:ff5bcb12ae60 3028:ab2696e34d29
1 #!/usr/bin/env python2 1 #!/usr/bin/env python3
2 # -*- coding: utf-8 -*- 2 # -*- coding: utf-8 -*-
3 3
4 # SAT plugin for managing xep-0264 4 # SAT plugin for managing xep-0264
5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org) 5 # Copyright (C) 2009-2019 Jérôme Poisson (goffi@goffi.org)
6 # Copyright (C) 2014 Emmanuel Gil Peyrot (linkmauve@linkmauve.fr) 6 # Copyright (C) 2014 Emmanuel Gil Peyrot (linkmauve@linkmauve.fr)
24 24
25 log = getLogger(__name__) 25 log = getLogger(__name__)
26 from twisted.internet import threads 26 from twisted.internet import threads
27 from twisted.python.failure import Failure 27 from twisted.python.failure import Failure
28 28
29 from zope.interface import implements 29 from zope.interface import implementer
30 30
31 from wokkel import disco, iwokkel 31 from wokkel import disco, iwokkel
32 32
33 from sat.core import exceptions 33 from sat.core import exceptions
34 import hashlib 34 import hashlib
35 35
36 try: 36 try:
37 from PIL import Image 37 from PIL import Image
38 except: 38 except:
39 raise exceptions.MissingModule( 39 raise exceptions.MissingModule(
40 u"Missing module pillow, please download/install it from https://python-pillow.github.io" 40 "Missing module pillow, please download/install it from https://python-pillow.github.io"
41 ) 41 )
42 42
43 #  cf. https://stackoverflow.com/a/23575424 43 #  cf. https://stackoverflow.com/a/23575424
44 from PIL import ImageFile 44 from PIL import ImageFile
45 45
49 from twisted.words.protocols.xmlstream import XMPPHandler 49 from twisted.words.protocols.xmlstream import XMPPHandler
50 except ImportError: 50 except ImportError:
51 from wokkel.subprotocols import XMPPHandler 51 from wokkel.subprotocols import XMPPHandler
52 52
53 53
54 MIME_TYPE = u"image/jpeg" 54 MIME_TYPE = "image/jpeg"
55 SAVE_FORMAT = u"JPEG" # (cf. Pillow documentation) 55 SAVE_FORMAT = "JPEG" # (cf. Pillow documentation)
56 56
57 NS_THUMBS = "urn:xmpp:thumbs:1" 57 NS_THUMBS = "urn:xmpp:thumbs:1"
58 58
59 PLUGIN_INFO = { 59 PLUGIN_INFO = {
60 C.PI_NAME: "XEP-0264", 60 C.PI_NAME: "XEP-0264",
72 class XEP_0264(object): 72 class XEP_0264(object):
73 SIZE_SMALL = (250, 250) 73 SIZE_SMALL = (250, 250)
74 SIZE_MEDIUM = (1024, 1024) 74 SIZE_MEDIUM = (1024, 1024)
75 75
76 def __init__(self, host): 76 def __init__(self, host):
77 log.info(_(u"Plugin XEP_0264 initialization")) 77 log.info(_("Plugin XEP_0264 initialization"))
78 self.host = host 78 self.host = host
79 host.trigger.add("XEP-0234_buildFileElement", self._addFileThumbnails) 79 host.trigger.add("XEP-0234_buildFileElement", self._addFileThumbnails)
80 host.trigger.add("XEP-0234_parseFileElement", self._getFileThumbnails) 80 host.trigger.add("XEP-0234_parseFileElement", self._getFileThumbnails)
81 81
82 def getHandler(self, client): 82 def getHandler(self, client):
84 84
85 ## triggers ## 85 ## triggers ##
86 86
87 def _addFileThumbnails(self, file_elt, extra_args): 87 def _addFileThumbnails(self, file_elt, extra_args):
88 try: 88 try:
89 thumbnails = extra_args[u"extra"][C.KEY_THUMBNAILS] 89 thumbnails = extra_args["extra"][C.KEY_THUMBNAILS]
90 except KeyError: 90 except KeyError:
91 return 91 return
92 for thumbnail in thumbnails: 92 for thumbnail in thumbnails:
93 thumbnail_elt = file_elt.addElement((NS_THUMBS, u"thumbnail")) 93 thumbnail_elt = file_elt.addElement((NS_THUMBS, "thumbnail"))
94 thumbnail_elt["uri"] = u"cid:" + thumbnail["id"] 94 thumbnail_elt["uri"] = "cid:" + thumbnail["id"]
95 thumbnail_elt["media-type"] = MIME_TYPE 95 thumbnail_elt["media-type"] = MIME_TYPE
96 width, height = thumbnail["size"] 96 width, height = thumbnail["size"]
97 thumbnail_elt["width"] = unicode(width) 97 thumbnail_elt["width"] = str(width)
98 thumbnail_elt["height"] = unicode(height) 98 thumbnail_elt["height"] = str(height)
99 return True 99 return True
100 100
101 def _getFileThumbnails(self, file_elt, file_data): 101 def _getFileThumbnails(self, file_elt, file_data):
102 thumbnails = [] 102 thumbnails = []
103 for thumbnail_elt in file_elt.elements(NS_THUMBS, u"thumbnail"): 103 for thumbnail_elt in file_elt.elements(NS_THUMBS, "thumbnail"):
104 uri = thumbnail_elt["uri"] 104 uri = thumbnail_elt["uri"]
105 if uri.startswith("cid:"): 105 if uri.startswith("cid:"):
106 thumbnail = {"id": uri[4:]} 106 thumbnail = {"id": uri[4:]}
107 width = thumbnail_elt.getAttribute("width") 107 width = thumbnail_elt.getAttribute("width")
108 height = thumbnail_elt.getAttribute("height") 108 height = thumbnail_elt.getAttribute("height")
142 if size is None: 142 if size is None:
143 size = self.SIZE_SMALL 143 size = self.SIZE_SMALL
144 try: 144 try:
145 img = Image.open(source_path) 145 img = Image.open(source_path)
146 except IOError: 146 except IOError:
147 return Failure(exceptions.DataError(u"Can't open image")) 147 return Failure(exceptions.DataError("Can't open image"))
148 148
149 img.thumbnail(size) 149 img.thumbnail(size)
150 uid = self.getThumbId(image_uid or source_path, size) 150 uid = self.getThumbId(image_uid or source_path, size)
151 151
152 with self.host.common_cache.cacheData( 152 with self.host.common_cache.cacheData(
174 174
175 d = threads.deferToThread( 175 d = threads.deferToThread(
176 self._blockingGenThumb, source_path, size, max_age, image_uid=image_uid 176 self._blockingGenThumb, source_path, size, max_age, image_uid=image_uid
177 ) 177 )
178 d.addErrback( 178 d.addErrback(
179 lambda failure_: log.error(u"thumbnail generation error: {}".format(failure_)) 179 lambda failure_: log.error("thumbnail generation error: {}".format(failure_))
180 ) 180 )
181 return d 181 return d
182 182
183 183
184 @implementer(iwokkel.IDisco)
184 class XEP_0264_handler(XMPPHandler): 185 class XEP_0264_handler(XMPPHandler):
185 implements(iwokkel.IDisco)
186 186
187 def getDiscoInfo(self, requestor, target, nodeIdentifier=""): 187 def getDiscoInfo(self, requestor, target, nodeIdentifier=""):
188 return [disco.DiscoFeature(NS_THUMBS)] 188 return [disco.DiscoFeature(NS_THUMBS)]
189 189
190 def getDiscoItems(self, requestor, target, nodeIdentifier=""): 190 def getDiscoItems(self, requestor, target, nodeIdentifier=""):