Skip to content

Commit

Permalink
added an optional secondary rendering engine that automatically handl…
Browse files Browse the repository at this point in the history
…es requests if the primary fails
  • Loading branch information
lucalianas committed Dec 6, 2016
1 parent 8c3ac4a commit 71876db
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 55 deletions.
12 changes: 6 additions & 6 deletions images_cache/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,22 +10,22 @@ class CacheDriverFactory(object):
def __init__(self):
self.cache_driver = settings.IMAGES_CACHE_DRIVER

def _get_fake_cache(self):
def _get_fake_cache(self, rendering_engine):
from fake_cache import FakeCache

return FakeCache()

def _get_redis_driver(self):
def _get_redis_driver(self, rendering_engine):
from redis_img_cache import RedisCache

return RedisCache(settings.REDIS_HOST, settings.REDIS_PORT, settings.REDIS_DB,
settings.CACHE_EXPIRE_TIME)
settings.CACHE_EXPIRE_TIME, rendering_engine)

def get_cache(self):
def get_cache(self, rendering_engine):
if not settings.IMAGES_CACHE_ENABLED:
return self._get_fake_cache()
return self._get_fake_cache(rendering_engine)
else:
if self.cache_driver == 'redis':
return self._get_redis_driver()
return self._get_redis_driver(rendering_engine)
else:
raise UnknownCacheDriver('There is no driver for %s' % self.cache_driver)
10 changes: 4 additions & 6 deletions images_cache/cache_interface.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from ome_seadragon import settings

from abc import ABCMeta, abstractmethod


Expand All @@ -8,19 +6,19 @@ class CacheInterface(object):
__metaclass__ = ABCMeta

@abstractmethod
def _get_tile_key(self, image_id, level, column, row, tile_size, image_format,
def _get_tile_key(self, engine, image_id, level, column, row, tile_size, image_format,
image_quality=None):
if image_quality:
image_format = '%s%s' % (image_format, image_quality)
return 'TILE::IMG_%s|L_%s|C_%s-R_%s|S_%spx|F_%s|E_%s' % (image_id, level, column, row,
tile_size, image_format.upper(),
settings.TILES_RENDERING_ENGINE)
engine)

@abstractmethod
def _get_thumbnail_key(self, image_id, thumbnail_size, image_format):
def _get_thumbnail_key(self, engine, image_id, thumbnail_size, image_format):
return 'THUMB::IMG_%s|S_%spx|F_%s|E_%s' % (image_id, thumbnail_size,
image_format.upper(),
settings.THUMBNAILS_RENDERING_ENGINE)
engine)

@abstractmethod
def tile_to_cache(self, image_id, image_obj, level, column, row, tile_size, image_format,
Expand Down
4 changes: 2 additions & 2 deletions images_cache/fake_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ class FakeCache(CacheInterface):
def __init__(self):
pass

def _get_tile_key(self, image_id, level, column, row, tile_size, image_format,
def _get_tile_key(self, engine, image_id, level, column, row, tile_size, image_format,
image_quality=None):
pass

def _get_thumbnail_key(self, image_id, thumbnail_size, image_format):
def _get_thumbnail_key(self, engine, image_id, thumbnail_size, image_format):
pass

def tile_to_cache(self, image_id, image_obj, level, column, row, tile_size, image_format,
Expand Down
23 changes: 12 additions & 11 deletions images_cache/redis_img_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,32 +8,33 @@

class RedisCache(CacheInterface):

def __init__(self, host, port, database, default_expire):
def __init__(self, host, port, database, default_expire, engine):
self.client = redis.StrictRedis(host=host, port=port, db=database)
self.default_expire_time = default_expire
self.logger = logging.getLogger(__name__)
self.engine = engine

def _get_tile_key(self, image_id, level, column, row, tile_size, image_format,
def _get_tile_key(self, engine, image_id, level, column, row, tile_size, image_format,
image_quality=None):
return super(RedisCache, self)._get_tile_key(image_id, level, column, row,
tile_size, image_format,
image_quality)
return super(RedisCache, self)._get_tile_key(engine, image_id, level, column, row,
tile_size, image_format, image_quality)

def _get_thumbnail_key(self, image_id, thumbnail_size, image_format):
return super(RedisCache, self)._get_thumbnail_key(image_id, thumbnail_size, image_format)
def _get_thumbnail_key(self, engine, image_id, thumbnail_size, image_format):
return super(RedisCache, self)._get_thumbnail_key(engine, image_id, thumbnail_size,
image_format)

def tile_to_cache(self, image_id, image_obj, level, column, row, tile_size, image_format,
image_quality=None):
out_buffer = StringIO()
image_obj.save(out_buffer, image_format)
tile_key = self._get_tile_key(image_id, level, column, row, tile_size,
tile_key = self._get_tile_key(self.engine, image_id, level, column, row, tile_size,
image_format.upper(), image_quality)
self.client.set(tile_key, out_buffer.getvalue())
self._set_expire_time(tile_key)

def tile_from_cache(self, image_id, level, column, row, tile_size, image_format,
image_quality=None):
tile_key = self._get_tile_key(image_id, level, column, row, tile_size,
tile_key = self._get_tile_key(self.engine, image_id, level, column, row, tile_size,
image_format.upper(), image_quality)
self.logger.info('Tile from cache: %s' % tile_key)
tile_str = self.client.get(tile_key)
Expand All @@ -51,12 +52,12 @@ def tile_from_cache(self, image_id, level, column, row, tile_size, image_format,
def thumbnail_to_cache(self, image_id, image_obj, thumbnail_size, image_format):
out_buffer = StringIO()
image_obj.save(out_buffer, image_format)
th_key = self._get_thumbnail_key(image_id, thumbnail_size, image_format)
th_key = self._get_thumbnail_key(self.engine, image_id, thumbnail_size, image_format)
self.client.set(th_key, out_buffer.getvalue())
self._set_expire_time(th_key)

def thumbnail_from_cache(self, image_id, thumbnail_size, image_format):
th_key = self._get_thumbnail_key(image_id, thumbnail_size, image_format)
th_key = self._get_thumbnail_key(self.engine, image_id, thumbnail_size, image_format)
self.logger.info('Thumbnail from cache: %s' % th_key)
img_str = self.client.get(th_key)
if img_str:
Expand Down
14 changes: 10 additions & 4 deletions settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,16 @@ def time_dict_to_seconds(value):
# <ome_home>/bin/omero config set omero.web.ome_seadragon.repository $(<ome_home>/bin/omero config get omero.data.dir)
'omero.web.ome_seadragon.repository': ['IMGS_REPOSITORY', None, identity, None],
'omero.web.ome_seadragon.images_folder': ['IMGS_FOLDER', 'ManagedRepository', identity, None],
# default rendering engine
'omero.web.ome_seadragon.tiles.rendering_engine': ['TILES_RENDERING_ENGINE', 'openslide', identity, None],
'omero.web.ome_seadragon.thumbnails.rendering_engine': ['THUMBNAILS_RENDERING_ENGINE', 'omero',
identity, None],
# default rendering engines
'omero.web.ome_seadragon.tiles.primary_rendering_engine': ['PRIMARY_TILES_RENDERING_ENGINE',
'openslide', identity, None],
'omero.web.ome_seadragon.thumbnails.primary_rendering_engine': ['PRIMARY_THUMBNAILS_RENDERING_ENGINE',
'omero', identity, None],
# secondary rendering engines
'omero.web.ome_seadragon.tiles.secondary_rendering_engine': ['SECONDARY_TILES_RENDERING_ENGINE',
'omero', identity, None],
'omero.web.ome_seadragon.thumbnails.secondary_rendering_engine': ['SECONDARY_THUMBNAILS_RENDERING_ENGINE',
'openslide', identity, None],
# deepzoom properties
'omero.web.ome_seadragon.deepzoom.overlap': ['DEEPZOOM_OVERLAP', 1, identity, None],
'omero.web.ome_seadragon.deepzoom.format': ['DEEPZOOM_FORMAT', 'jpeg', identity, None],
Expand Down
42 changes: 30 additions & 12 deletions slides_manager/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,16 @@ class UnknownRenderingEngine(Exception):
class RenderingEngineFactory(object):

def __init__(self):
self.tiles_rendering_engine = settings.TILES_RENDERING_ENGINE
self.thumbnails_rendering_engine = settings.THUMBNAILS_RENDERING_ENGINE
self.primary_tiles_rendering_engine = settings.PRIMARY_TILES_RENDERING_ENGINE
self.primary_thumbnails_rendering_engine = settings.PRIMARY_THUMBNAILS_RENDERING_ENGINE
try:
self.secondary_tiles_rendering_engine = settings.SECONDARY_TILES_RENDERING_ENGINE
except AttributeError:
self.secondary_tiles_rendering_engine = None
try:
self.secondary_thumbnails_rendering_engine = settings.SECONDARY_THUMBNAILS_RENDERING_ENGINE
except AttributeError:
self.secondary_thumbnails_rendering_engine = None

def _get_openslide_engine(self, image_id, connection):
from openslide_engine import OpenSlideEngine
Expand All @@ -21,18 +29,28 @@ def _get_omero_engine(self, image_id, connection):

return OmeEngine(image_id, connection)

def get_tiles_rendering_engine(self, image_id, connection):
if self.tiles_rendering_engine == 'openslide':
def _get_engine(self, engine, image_id, connection):
if engine == 'openslide':
return self._get_openslide_engine(image_id, connection)
if self.tiles_rendering_engine == 'omero':
if engine == 'omero':
return self._get_omero_engine(image_id, connection)
else:
raise UnknownRenderingEngine('%s is not a valid rendering engine' % self.tiles_rendering_engine)
raise UnknownRenderingEngine('%s is not a valid rendering engine' % self.primary_thumbnails_rendering_engine)

def get_thumbnails_rendering_engine(self, image_id, connection):
if self.thumbnails_rendering_engine == 'openslide':
return self._get_openslide_engine(image_id, connection)
if self.thumbnails_rendering_engine == 'omero':
return self._get_omero_engine(image_id, connection)
def get_primary_tiles_rendering_engine(self, image_id, connection):
return self._get_engine(self.primary_tiles_rendering_engine, image_id, connection)

def get_primary_thumbnails_rendering_engine(self, image_id, connection):
return self._get_engine(self.primary_thumbnails_rendering_engine, image_id, connection)

def get_secondary_tiles_rendering_engine(self, image_id, connection):
if self.secondary_tiles_rendering_engine:
return self._get_engine(self.secondary_tiles_rendering_engine, image_id, connection)
else:
return None

def get_secondary_thumbnails_rendering_engine(self, image_id, connection):
if self.secondary_thumbnails_rendering_engine:
return self._get_engine(self.secondary_thumbnails_rendering_engine, image_id, connection)
else:
raise UnknownRenderingEngine('%s is not a valid rendering engine' % self.thumbnails_rendering_engine)
return None
4 changes: 2 additions & 2 deletions slides_manager/ome_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ def get_dzi_description(self, original_file_source=False, file_mimetype=None):

def get_thumbnail(self, size, original_file_source=False, file_mimeype=None):
self._check_source_type(original_file_source)
cache = CacheDriverFactory().get_cache()
cache = CacheDriverFactory().get_cache('omero')
thumbnail = cache.thumbnail_from_cache(self.image_id, size,
settings.DEEPZOOM_FORMAT)
if thumbnail is None:
Expand All @@ -175,7 +175,7 @@ def get_thumbnail(self, size, original_file_source=False, file_mimeype=None):

def get_tile(self, level, column, row, original_file_source=False, file_mimetype=None):
self._check_source_type(original_file_source)
cache = CacheDriverFactory().get_cache()
cache = CacheDriverFactory().get_cache('omero')
cache_params = {
'image_id': self.image_id,
'level': level,
Expand Down
4 changes: 2 additions & 2 deletions slides_manager/openslide_engine.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ def get_dzi_description(self, original_file_source=False, file_mimetype=None):
return None

def get_thumbnail(self, size, original_file_source=False, file_mimeype=None):
cache = CacheDriverFactory().get_cache()
cache = CacheDriverFactory().get_cache('openslide')
# get thumbnail from cache
thumb = cache.thumbnail_from_cache(self.image_id, size,
settings.DEEPZOOM_FORMAT)
Expand All @@ -78,7 +78,7 @@ def get_thumbnail(self, size, original_file_source=False, file_mimeype=None):
return thumb, settings.DEEPZOOM_FORMAT

def get_tile(self, level, column, row, original_file_source=False, file_mimetype=None):
cache = CacheDriverFactory().get_cache()
cache = CacheDriverFactory().get_cache('openslide')
cache_params = {
'image_id': self.image_id,
'level': level,
Expand Down
54 changes: 44 additions & 10 deletions views.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,16 @@ def find_annotations(request, conn=None, **kwargs):
@login_required()
def get_image_dzi(request, image_id, fetch_original_file=False,
file_mimetype=None, conn=None, **kwargs):
rendering_engine = RenderingEngineFactory().get_tiles_rendering_engine(image_id, conn)
dzi_metadata = rendering_engine.get_dzi_description(fetch_original_file, file_mimetype)
rf = RenderingEngineFactory()
rendering_engine = rf.get_primary_tiles_rendering_engine(image_id, conn)
try:
dzi_metadata = rendering_engine.get_dzi_description(fetch_original_file, file_mimetype)
except Exception, e:
rendering_engine = rf.get_secondary_tiles_rendering_engine(image_id, conn)
if rendering_engine:
dzi_metadata = rendering_engine.get_dzi_description(fetch_original_file, file_mimetype)
else:
raise e
if dzi_metadata:
return HttpResponse(dzi_metadata, content_type='application/xml')
else:
Expand All @@ -207,9 +215,18 @@ def get_image_dzi(request, image_id, fetch_original_file=False,
@login_required()
def get_image_thumbnail(request, image_id, fetch_original_file=False,
file_mimetype=None, conn=None, **kwargs):
rendering_engine = RenderingEngineFactory().get_thumbnails_rendering_engine(image_id, conn)
thumbnail, image_format = rendering_engine.get_thumbnail(int(request.GET.get('size')),
fetch_original_file, file_mimetype)
rf = RenderingEngineFactory()
rendering_engine = rf.get_primary_thumbnails_rendering_engine(image_id, conn)
try:
thumbnail, image_format = rendering_engine.get_thumbnail(int(request.GET.get('size')),
fetch_original_file, file_mimetype)
except Exception, e:
rendering_engine = rf.get_secondary_thumbnail_rendering_engine(image_id, conn)
if rendering_engine:
thumbnail, image_format = rendering_engine.get_thumbnail(int(request.GET.get('size')),
fetch_original_file, file_mimetype)
else:
raise e
if thumbnail:
response = HttpResponse(content_type="image/%s" % image_format)
thumbnail.save(response, image_format)
Expand All @@ -223,9 +240,18 @@ def get_tile(request, image_id, level, column, row, tile_format,
fetch_original_file=False, file_mimetype=None, conn=None, **kwargs):
if tile_format != settings.DEEPZOOM_FORMAT:
return HttpResponseServerError("Format %s not supported by the server" % tile_format)
rendering_engine = RenderingEngineFactory().get_tiles_rendering_engine(image_id, conn)
tile, image_format = rendering_engine.get_tile(int(level), int(column), int(row),
fetch_original_file, file_mimetype)
rf = RenderingEngineFactory()
rendering_engine = rf.get_primary_tiles_rendering_engine(image_id, conn)
try:
tile, image_format = rendering_engine.get_tile(int(level), int(column), int(row),
fetch_original_file, file_mimetype)
except Exception, e:
rendering_engine = rf.get_secondary_tiles_rendering_engine(image_id, conn)
if rendering_engine:
tile, image_format = rendering_engine.get_tile(int(level), int(column), int(row),
fetch_original_file, file_mimetype)
else:
raise e
if tile:
response = HttpResponse(content_type='image/%s' % image_format)
tile.save(response, image_format)
Expand All @@ -237,8 +263,16 @@ def get_tile(request, image_id, level, column, row, tile_format,
@login_required()
def get_image_mpp(request, image_id, fetch_original_file=False,
file_mimetype=None, conn=None, **kwargs):
rendering_engine = RenderingEngineFactory().get_tiles_rendering_engine(image_id, conn)
image_mpp = rendering_engine.get_openseadragon_config(fetch_original_file, file_mimetype)['mpp']
rf = RenderingEngineFactory()
rendering_engine = rf.get_primary_tiles_rendering_engine(image_id, conn)
try:
image_mpp = rendering_engine.get_openseadragon_config(fetch_original_file, file_mimetype)['mpp']
except Exception, e:
rendering_engine = rf.get_secondary_tiles_rendering_engine(image_id, conn)
if rendering_engine:
image_mpp = rendering_engine.get_openseadragon_config(fetch_original_file, file_mimetype)['mpp']
else:
raise e
return HttpResponse(json.dumps({'image_mpp': image_mpp}), content_type='application/json')


Expand Down

0 comments on commit 71876db

Please sign in to comment.