Package gavo :: Package web :: Module asyncrender
[frames] | no frames]

Source Code for Module gavo.web.asyncrender

  1  """ 
  2  Renderers and helpers for asynchronous services. 
  3   
  4  For TAP (which was the first prototype of these), there's a separate 
  5  module using some of this; on the long run, it should probably be 
  6  integrated here. 
  7  """ 
  8   
  9  #c Copyright 2008-2019, the GAVO project 
 10  #c 
 11  #c This program is free software, covered by the GNU GPL.  See the 
 12  #c COPYING file in the source distribution. 
 13   
 14   
 15  from nevow import inevow 
 16  from nevow import rend 
 17  from twisted.internet import defer 
 18   
 19  from gavo import base 
 20  from gavo import svcs 
 21  from gavo import utils 
 22  from gavo.protocols import uws 
 23  from gavo.protocols import uwsactions 
24 25 26 -class UWSRedirect(rend.Page):
27 """a redirection for UWS (i.e., 303). 28 29 The DC-global redirects use a 302 status, munge redirection URLs, and 30 we don't want any HTML payload here anyway. 31 32 The locations used here are relative to baseURL, which essentially 33 has to be the the full absolute URL of the endpoint (i.e., 34 service/renderer). As a special service, for TAP async is being 35 added as long as the renderer isn't fixed to not do dispatching. 36 """
37 - def __init__(self, baseURL, location):
38 # TODO: Temporary hack as long as TAP isn't modernized to use 39 # an async renderer: fix the redirect to TAP's async endpoint if 40 # baseURL is the TAP renderer: 41 if baseURL.endswith("tap"): 42 baseURL = baseURL+"/async" 43 44 if location: 45 if location.startswith("http://") or location.startswith("https://"): 46 self.location = str(location) 47 else: 48 self.location = str( 49 "%s/%s"%(baseURL, location)) 50 else: 51 self.location = str(baseURL)
52
53 - def renderHTTP(self, ctx):
54 req = inevow.IRequest(ctx) 55 req.code = 303 56 req.setHeader("location", self.location) 57 req.setHeader("content-type", "text/plain") 58 req.write("Go here: %s\n"%self.location) 59 return ""
60
61 62 -class MethodAwareResource(rend.Page):
63 """is a rend.Page with behaviour depending on the HTTP method. 64 """
65 - def __init__(self, workerSystem, renderer, service):
66 self.workerSystem, self.service = workerSystem, service 67 self.renderer = renderer 68 rend.Page.__init__(self)
69
70 - def _doBADMETHOD(self, ctx, request):
71 raise svcs.BadMethod(request.method)
72
73 - def renderHTTP(self, ctx):
74 request = inevow.IRequest(ctx) 75 handlingMethod = getattr(self, "_do"+request.method, self._doBADMETHOD) 76 return defer.maybeDeferred(handlingMethod, ctx, request 77 ).addCallback(self._deliverResult, request 78 ).addErrback(self._deliverError, request)
79
80 81 -class UWSErrorMixin(object):
82 - def _deliverError(self, failure, request):
83 # let auth requests fall through 84 if isinstance(failure.value, svcs.Authenticate): 85 return failure 86 87 if not isinstance(failure.value, uws.JobNotFound): 88 base.ui.notifyFailure(failure) 89 request.setHeader("content-type", "text/xml") 90 return uwsactions.ErrorResource(failure.value)
91
92 93 -class JoblistResource(MethodAwareResource, UWSErrorMixin):
94 """The web resource corresponding to async root. 95 96 GET yields a job list, POST creates a job. 97 98 There's an extra hack not in UWS: if get with something like 99 dachs_authenticate=anything and haven't passed a user, this will ask 100 for credentials. 101 """ 102 @utils.memoized
103 - def getJoblistInputTD(self):
104 return base.parseFromString(svcs.InputTD, 105 """ 106 <inputTable> 107 <inputKey name="PHASE" type="text" multiplicity="single" 108 description="Restrict result to jobs in this phase"> 109 <values> 110 <option>PENDING</option> 111 <option>QUEUED</option> 112 <option>EXECUTING</option> 113 <option>COMPLETED</option> 114 <option>ERROR</option> 115 <option>ABORTED</option> 116 <option>UNKNOWN</option> 117 <option>HELD</option> 118 <option>SUSPENDED</option> 119 <option>ARCHIVED</option> 120 </values> 121 </inputKey> 122 <inputKey name="AFTER" type="timestamp" multiplicity="single" 123 description="Restrict result to jobs created 124 after this point in time"/> 125 <inputKey name="LAST" type="integer" multiplicity="single" 126 description="Restrict output to this many records, and choose the 127 most recent ones"/> 128 </inputTable>""")
129
130 - def _doGET(self, ctx, request):
131 if "dachs_authenticate" in request.args and not request.getUser(): 132 raise svcs.Authenticate() 133 134 args = svcs.CoreArgs.fromRawArgs( 135 self.getJoblistInputTD(), 136 request.args).args 137 138 res = uwsactions.getJobList(self.workerSystem, 139 request.getUser() or None, 140 phase=args["PHASE"], 141 last=args["LAST"], 142 after=args["AFTER"]) 143 return res
144
145 - def _doPOST(self, ctx, request):
149
150 - def _deliverResult(self, res, request):
151 request.setHeader("content-type", "text/xml") 152 return res
153
154 155 -class JobResource(rend.Page, UWSErrorMixin):
156 """The web resource corresponding to async requests for jobs. 157 """
158 - def __init__(self, workerSystem, renderer, service, segments):
159 self.service, self.segments = service, segments 160 self.workerSystem, self.renderer = workerSystem, renderer
161
162 - def renderHTTP(self, ctx):
163 request = inevow.IRequest(ctx) 164 return defer.maybeDeferred( 165 uwsactions.doJobAction, self.workerSystem, request, self.segments 166 ).addCallback(self._deliverResult, request 167 ).addErrback(self._redirectAsNecessary, ctx 168 ).addErrback(self._deliverError, request)
169
170 - def _redirectAsNecessary(self, failure, ctx):
171 failure.trap(svcs.WebRedirect) 172 return UWSRedirect(self.service.getURL(self.renderer), 173 failure.value.rawDest)
174
175 - def _deliverResult(self, result, request):
176 if hasattr(result, "renderHTTP"): # it's a finished resource 177 return result 178 # content-type is set by uwsaction._JobActions.dispatch 179 request.write(utils.xmlrender(result).encode("utf-8")) 180 return ""
181
182 183 -def getAsyncResource(ctx, workerSystem, renderer, service, segments):
184 if segments: 185 return JobResource(workerSystem, renderer, service, segments) 186 else: 187 return JoblistResource(workerSystem, renderer, service)
188