File: productrender.py

package info (click to toggle)
gavodachs 2.3%2Bdfsg-3
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 7,260 kB
  • sloc: python: 58,359; xml: 8,882; javascript: 3,453; ansic: 661; sh: 158; makefile: 22
file content (121 lines) | stat: -rw-r--r-- 4,629 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
"""
Code dealing with product (i.e., fits file) delivery.
"""

#c Copyright 2008-2020, the GAVO project
#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


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==')

	def render(self, request):
		request.setResponseCode(404)
		request.setHeader("content-type", "image/png")
		request.write(self.noPreviewImg)
		request.finish()

_MISSING_PREVIEW = MissingPreview()


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 = ""

	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()

	def getChild(self, name, request):
		self.pathFromSegments = "/".join(request.popSegments(name))
		return self