X-Git-Url: https://scm.cri.ensmp.fr/git/Portfolio.git/blobdiff_plain/2da869b2b46179d64c05eaac4081226fdbbbc9ff..e73353500c67453ef9663d67eaeee7dd46c358ee:/Products/Portfolio/manipulation.py diff --git a/Products/Portfolio/manipulation.py b/Products/Portfolio/manipulation.py new file mode 100755 index 0000000..af010a5 --- /dev/null +++ b/Products/Portfolio/manipulation.py @@ -0,0 +1,145 @@ +# -*- coding: utf-8 -*- +############################################################ +# Copyright © 2005-2010 Benoît PIN # +# Plinn - http://plinn.org # +# # +# This program is free software; you can redistribute it # +# and/or modify it under the terms of the Creative Commons # +# "Attribution-Noncommercial 2.0 Generic" # +# http://creativecommons.org/licenses/by-nc/2.0/ # +############################################################ +""" Image threaded batch computation module +""" + +import threading +import logging +import atexit +from types import StringTypes +from math import ceil +import transaction +from ZODB.POSException import ConflictError +from ZODB.POSException import ConnectionStateError +from zope.site.hooks import setSite +from cStringIO import StringIO + +console = logging.getLogger('[manipulation thread]') + +class ImageQueueProcessorThread(threading.Thread) : + """This thread is started at zope startup + """ + + __stopped = False + + + def __init__(self, portal_path, itemsPath) : + threading.Thread.__init__(self) + self.portal_path = portal_path + self.queue = [] + if isinstance(itemsPath, StringTypes) : + itemsPath = [itemsPath] + for i in itemsPath : + self.queueAdd(i) + + @property + def queueSize(self) : + return len(self.queue) + + def queueAdd(self, itemPath) : + self.queue.append(itemPath) + + def run(self) : + console.info('process started.') + #atexit.register(self.stop) + import Zope2 + app = Zope2.app() + portal = app.unrestrictedTraverse(self.portal_path) + setSite(portal) + while not self.__stopped and self.queueSize : + self._process(app) + + con = app._p_jar + try : + con.close() + except ConnectionStateError, e : + console.warn('ConnectionStateError raised before finished.') + console.info('process finished.') + + + def stop(self): + console.info('process stopped.') + self.__stopped = True + + def _process(self, app) : + path = self.queue.pop(0) + try : + p = app.unrestrictedTraverse(path) + except KeyError : + console.warn('deleted during processing: %s' % path) + return + + console.info('%d : %s' % (self.queueSize, p.absolute_url())) + + try : + if not hasattr(p, 'thumbnail'): + p.makeThumbnail() + # print 'make thumbnail' + + for size in ((500, 500), (600, 600), (800, 800)) : + # print 'resize at', size + p._getResizedImage(size, True) + transaction.commit() + + zMin = p.tiles_min_zoom + zMax = p.tiles_max_zoom + zStep = p.tiles_step_zoom + levels = range(zMin, zMax + zStep, zStep) + zooms = [l/100. for l in levels] + todo = set(zooms) - set(p._tiles.keys()) + if todo : + if p.tileGenerationLock.locked() : + console.info('skip %s: already tiling.' % p.absolute_url()) + return + + p.tileGenerationLock.acquire() + zooms = list(todo) + zooms.sort() + ppm = None + try : + ppm = p._getPPM() + for zoom in zooms : + + # print 'tiling at', zoom + if zoom < 1 : + rppm = ppm.resize(ratio=zoom) + else : + rppm = ppm + p._makeTilesAt(zoom, rppm) + del rppm + transaction.commit() + finally : + del ppm + p.tileGenerationLock.release() + + try : + delattr(p, '_v__methodResultsCache') + except AttributeError: + pass + + p.tiles_available = 1 + assert p._getCatalogTool() + p.reindexObject(idxs=['tiles_available']) + transaction.commit() + + except ConflictError : + console.warn('Resync after ZODB ConflicError') + transaction.abort() + portal = app.unrestrictedTraverse(self.portal_path) + portal._p_jar.sync() + self.queueAdd(path) + return + except : + p.tiles_available = -1 + import traceback + out = StringIO() + traceback.print_exc(None, out) + console.error(out.getvalue())