Source code for gavo.web.productrender

"""
Code dealing with product (i.e., fits file) delivery.
"""

#c Copyright 2008-2023, the GAVO project <gavo@ari.uni-heidelberg.de>
#c
#c This program is free software, covered by the GNU GPL.  See the
#c COPYING file in the source distribution.


import base64

from twisted.web import resource
from twisted.web import server

from gavo import base
from gavo import utils
from gavo.protocols import products
from gavo.web import grend
from gavo.web import weberrors


[docs]class MissingPreview(resource.Resource): """A twisted resource returning a 404 image. """ noPreviewImg = base64.b64decode( 'iVBORw0KGgoAAAANSUhEUgAAAMgAAABkAgMAAAC+6JeYAAAADFBMV' 'EUQEg9OUE2Qko/8//texVsLAAAAAWJLR0QAiAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAA' 'Ad0SU1FB+QIDAwjFnjAPBkAAAK0SURBVFjD7dQ/aBNRHAfwbh0ydCoiBzlUcEpz4CBC/zzo0' 'EVQqKOgg0MRioKDZLiagmKHgsF20amUCiJCtVAhyl0eWNpAb2jTGwp1ae8NRRya97zAS3t3P' '393bcy1TaEddOlluPfL5T653yXv+2uDM7/aEpKQhCQkIQk5f6Su/D0RkLWA4FprXiNaEWeyS' 'bTvfh5X3nifb02s2BnthUdjxCetSRncxxtP3/rhteobz1TAv+Qr4E3DgEyBGKsrUz8qFF7TJ' 'qnQdWtxbtgI69vDRc6A85oATx/RTQLVuT1WWEkTKJEmkalxe6Hq5cK60POFCXC44yLJmb0EO' 'TjWK6Lhc8Z+ZLvAyjy4HpbLvU+2BpEwCZ6RC5AIHkys3+vU4GeciAKzBFwOy6Vn1xgAO0SEw' '7LYVDZGdsS4jeRO9FylKw5+R9SYETUmOHOcPuyrL0aWnpfHkYztYr1J2/ku8C3uINFzpe6Qr' '1WJ+inoihFXdTUklot1FW76KfCv4sEz8/2ggKjJIUlXKbzMH9tjK2ffllNnJjKfBPnfE20/u' 'h3R4tEonbXTEBkdtw8IBnq7MQRObMzdT1AEImI3hkCcbKgbIxhvWvlar8MmGfDfw6gxHQTtO' 'APqymhpQKqVYurwuBhbnMN4a+kb1Rq4vm7cxbtk9OIehniP2YFkO+new3ex7AUmrEKWZOYFu' 'NLsIUh0vYgTDnNvg5wJSNcRwspbg+v3s52ZDzNIgp48EkM3FCTBhA3vPj/qPEYsBkzLEv/hg' '4jQiNBJnAHCsb1i6RbxjzZmOeCQrBakL0SNHRAR5d6Wki5rRwgmn+9WiabOdqTA9XIGBWYY+' 'rffOAOcNVac/7iiznb/ipNFzfJTkmqrVO2AOvTjf8INUzfDGSCHeOmiix8p9klj/JR77P+QJ' 'MgJSUhCEnJ+yB+3JLSzGAuzmQAAAABJRU5ErkJggg==')
[docs] def render(self, request): request.setResponseCode(404) request.setHeader("content-type", "image/png") request.write(self.noPreviewImg) request.finish()
_MISSING_PREVIEW = MissingPreview()
[docs]class ProductRenderer(grend.ServiceBasedPage): """The renderer used for delivering products. This will only work with a ProductCore since the resulting data set has to contain products.Resources. Thus, you probably will not use this in user RDs. """ name = "get" pathFromSegments = ""
[docs] def render(self, request): data = {"accref": products.RAccref.fromRequest(self.pathFromSegments, request)} # deferring here and going to all the trouble of running a core # is probably overkill; currently, the main thing that'd require # handwork is figuring out authentication in parallel with what # needs to be done for tar files. We should do better, indded. self.runAsyncWithFormalData(data, request ).addCallback(self._deliver, request ).addErrback(weberrors.renderDCErrorPage, request) return server.NOT_DONE_YET
def _deliver(self, result, request): doPreview = self.queryMeta.ctxArgs.get("preview") product = result[0] # This catches cases where people want previews of processed # products (in particular cutouts). I doubt this is a good # idea, but getting out of this hack again is hard. try: if doPreview and not "Preview" in product.__class__.__name__: return products.PreviewCacheManager.getPreviewFor(product ).addCallback(self._deliverPreview, product, request ).addErrback(self._deliverPreviewFailure, request) except base.DataError: return _MISSING_PREVIEW.render(request) else: if hasattr(product, "render"): res = product.render(request) if res not in (None, b"", server.NOT_DONE_YET): base.ui.notifyError("Product.render returned nonempty result" " %s. This is no longer supported, and the client won't see it."% utils.makeEllipsis(repr(res))) else: base.ui.notifyWarning("Non-product result in product renderer:" " %s"%repr(product)) from gavo.svcs import streaming return streaming.streamOut(lambda w, q: w.write(product), request) def _deliverPreview(self, content, product, request): previewMime = product.pr["preview_mime"] or "image/jpeg" request.setHeader("content-type", str(previewMime)) request.setHeader("content-length", str(len(content))) request.write(content) request.finish() def _deliverPreviewFailure(self, failure, request): failure.printTraceback() data = b"Not an image (preview generation failed, please report)" request.setResponseCode(500) request.setHeader("content-type", "text/plain") request.setHeader("content-length", str(len(data))) request.write(data) request.finish()
[docs] def getChild(self, name, request): self.pathFromSegments = "/".join(request.popSegments(name)) return self