8c057d6312ee393c03865f0cb6526cdf26233291
[Portfolio.git] / manipulation.py
1 # -*- coding: utf-8 -*-
2 ####################################################
3 # Copyright © 2009 Luxia SAS. All rights reserved. #
4 # #
5 # Contributors: #
6 # - Benoît Pin <pinbe@luxia.fr> #
7 ####################################################
8 """ Image threaded batch computation module
9
10 $Id: manipulation.py 1391 2009-09-16 23:36:05Z pin $
11 $URL: http://svn.luxia.fr/svn/labo/projects/zope/Portfolio/trunk/manipulation.py $
12 """
13
14 import threading
15 import logging
16 import atexit
17 from types import StringTypes
18 #import Zope2
19 from math import ceil
20 import transaction
21 from ZODB.POSException import ConflictError
22 from cStringIO import StringIO
23
24 console = logging.getLogger('[manipulation thread]')
25
26 class ImageQueueProcessorThread(threading.Thread) :
27 """This thread is started at zope startup
28 """
29
30 __stopped = False
31
32
33 def __init__(self, portal_path, itemsPath) :
34 threading.Thread.__init__(self)
35 self.portal_path = portal_path
36 self.queue = []
37 if isinstance(itemsPath, StringTypes) :
38 itemsPath = [itemsPath]
39 for i in itemsPath :
40 self.queueAdd(i)
41
42 # def __init__(self, portal_path, itemPath):
43 # threading.Thread.__init__(self)
44 # self.app = app = Zope2.app()
45 # self.portal = portal = app.unrestrictedTraverse(portal_path)
46 # self.imgTool = portal.portal_image_manipulation
47 # self.queue = []
48 # if itemPath :
49 # self.queueAdd(itemPath)
50 # else :
51 # ctool = portal.portal_catalog
52 # brains = ctool.unrestrictedSearchResults(portal_type='Photo', tiles_available=0)
53 # for b in brains :
54 # self.queueAdd(b.getPath())
55
56 def __del__(self) :
57 print "ayé, c'est la fin !"
58
59 @property
60 def queueSize(self) :
61 return len(self.queue)
62
63 def queueAdd(self, itemPath) :
64 self.queue.append(itemPath)
65
66 def run(self) :
67 console.info('process started.')
68 #atexit.register(self.stop)
69 import Zope2
70 app = Zope2.app()
71 while not self.__stopped and self.queueSize :
72 self._process(app)
73
74 con = app._p_jar
75 con.close()
76 #con.close()
77 console.info('process finished.')
78 #print con
79 #print con.transaction_manager
80
81
82 def stop(self):
83 console.info('process stopped.')
84 self.__stopped = True
85
86 def _process(self, app) :
87
88 path = self.queue.pop(0)
89
90 #import Zope2
91 #app = Zope2.app()
92
93 try :
94 p = app.unrestrictedTraverse(path)
95 except KeyError :
96 console.warn('deleted during processing: %s' % path)
97 return
98
99 console.info('%d : %s' % (self.queueSize, p.absolute_url()))
100
101 try :
102 if not hasattr(p, 'thumbnail'):
103 p.makeThumbnail()
104 # print 'make thumbnail'
105
106 for size in ((500, 500), (600, 600), (800, 800)) :
107 # print 'resize at', size
108 p._getResizedImage(size, True)
109 transaction.commit()
110
111 zMin = p.tiles_min_zoom
112 zMax = p.tiles_max_zoom
113 zStep = p.tiles_step_zoom
114 levels = range(zMin, zMax + zStep, zStep)
115 zooms = [l/100. for l in levels]
116 todo = set(zooms) - set(p._tiles.keys())
117 if todo :
118 if p.tileGenerationLock.locked() :
119 console.info('skip %s: already tiling.' % p.absolute_url())
120 return
121
122 p.tileGenerationLock.acquire()
123 zooms = list(todo)
124 zooms.sort()
125 ppm = None
126 try :
127 ppm = p._getPPM()
128 for zoom in zooms :
129
130 # print 'tiling at', zoom
131 if zoom < 1 :
132 rppm = ppm.resize(ratio=zoom)
133 else :
134 rppm = ppm
135 p._makeTilesAt(zoom, rppm)
136 del rppm
137 transaction.commit()
138 finally :
139 del ppm
140 p.tileGenerationLock.release()
141
142 try :
143 delattr(p, '_v__methodResultsCache')
144 except AttributeError:
145 pass
146
147 p.tiles_available = 1
148 p.reindexObject(idxs=['tiles_available'])
149 transaction.commit()
150
151 except ConflictError :
152 console.warn('Resync after ZODB ConflicError')
153 transaction.abort()
154 portal = app.unrestrictedTraverse(portal_path)
155 portal._p_jar.sync()
156 self.queueAdd(path)
157 return
158 except :
159 p.tiles_available = -1
160 import traceback
161 out = StringIO()
162 traceback.print_exc(None, out)
163 console.error(out.getvalue())