def __init__(self, kernel, clientObj): self.kernel = kernel self.dispatcher = kernel.dispatcher self.routingTable = kernel.routingTable self.requestInterface = PelotonRequestInterface(kernel) self.logger = kernel.logger self.clientObj = clientObj self.eventHandlers=[]
def __init__(self, kernel): AbstractPelotonAdapter.__init__(self, kernel, 'HTTP Adapter') resource.Resource.__init__(self) self.logger = kernel.logger self.requestInterface = PelotonRequestInterface(kernel) self.xmlrpcHandler = PelotonXMLRPCHandler(kernel) # setup info template loader from peloton.utils.transforms import template source=os.path.split(__file__)[0].split(os.sep) source.extend(['templates','request_info.html.genshi']) self.infoTemplate = template({}, "/".join(source))
class PelotonHTTPAdapter(AbstractPelotonAdapter, resource.Resource): """ The HTTP adapter provides for accessing methods over HTTP and receiving the results in a desired format. The main interface is rest-like but it also provides XMLRPC. Strictly speaking this isn't true rest: URIs refer to services not resources and session tracking is used. But... well... """ isLeaf = True def __init__(self, kernel): AbstractPelotonAdapter.__init__(self, kernel, 'HTTP Adapter') resource.Resource.__init__(self) self.logger = kernel.logger self.requestInterface = PelotonRequestInterface(kernel) self.xmlrpcHandler = PelotonXMLRPCHandler(kernel) # setup info template loader from peloton.utils.transforms import template source=os.path.split(__file__)[0].split(os.sep) source.extend(['templates','request_info.html.genshi']) self.infoTemplate = template({}, "/".join(source)) def start(self): """ Implement to initialise the adapter. This method must also hook this adapter into the reactor, probably calling reactor.listenTCP or adding itself to another protocol as a resource (this is the case for most HTTP based adapters).""" try: self.connection = reactor.listenTCP(self.kernel.settings.httpPort, server.Site(self), interface=self.kernel.profile.bind_interface) except CannotListenError: self.kernel.logger.info("Cannot start HTTP interface: port %s in use" % \ self.kernel.settings.httpPort) self.connection = None def render_GET(self, request): return self.render_POST(request) def render_POST(self, request): if request.postpath and request.postpath[0] == "RPC2": return self.xmlrpcHandler._resource.render(request) elif request.postpath and request.postpath[0] == "static": profile, _ = \ self.kernel.serviceLibrary.getProfile(request.postpath[1]) resourceRoot = profile['resourceRoot'] self.deliverStaticContent(resourceRoot, request.postpath[2:], request) elif request.postpath and request.postpath[0] == "fireEvent": self.fireEvent(request.postpath[1:], request) elif request.postpath and request.postpath[0] == "inspect": resp = self.infoTemplate({'rq':request}, {}) self.deferredResponse(resp, 'html', None, 'text/html',request) elif request.postpath and request.postpath[0] == "favicon.ico": self.returnFavicon(request) else: if request.postpath[-1] == '': request.postpath = request.postpath[:-1] try: service, method = request.postpath[:2] except ValueError: if len(request.postpath) == 1: service = request.postpath[0] method = 'index' else: raise ServiceError("Method or service not found for %s " % str(request.postpath)) split = method.split('.') if len(split)==1: target = 'html' else: method, target = split args = request.postpath[2:] kwargs={} # JSON requests which set the callback argument will get a JSONP formatted response callbackName = None for k,v in request.args.items(): self.kernel.logger.debug("Key %s value %s" % (k,v)) if target == 'json' and k == 'callback': callbackName = v[0] elif len(v) == 1: kwargs[k] = v[0] else: kwargs[k] = v self.kernel.logger.info("Callback name %s" % callbackName) try: profile, _ = self.kernel.serviceLibrary.getProfile(service) mimeType = profile['methods'][method]['properties']['mimetype.%s'%target] except: try: mimeType = {'html':'text/html', 'xml':'text/xml', 'json':'text/plain', 'raw':'text/plain'}[target] except KeyError: mimeType = 'text/plain' sessionId="TOBESORTED" d = self.requestInterface.public_call(sessionId, target, service, method, args, kwargs ) d.addCallback(self.deferredResponse, target, callbackName, mimeType, request) d.addErrback(self.deferredError, target, request) return server.NOT_DONE_YET def fireEvent(self, args, request): """ Fire an event on the message bus. Payload is the request arguments dictionary with an additional key, __peloton_args__ with the request arguments list. args[0] is the channel on which to fire the event. args[1] is the exchange """ payload = request.args payload['__peloton_args'] = args[2:] self.kernel.dispatcher.fireEvent(args[0], args[1], **payload) request.write("OK") request.finish() def returnFavicon(self, request): request.setHeader('Content-Type','image/x-icon') thisDir = os.path.split(__file__)[0] iconPath = "%s/favicon.ico" % thisDir fsize = os.stat(iconPath)[6] request.setHeader('Content-Length',fsize) res = open(iconPath, 'rb') FileTransfer(res, fsize, request) def deferredResponse(self, resp, target, callbackName, mimeType, request): # str ensures not unicode which is not liked by # twisted.web resp = str(resp) if target == 'json' and callbackName: resp = "%s(%s)" % (callbackName, resp) request.setHeader('Content-Type', mimeType) request.setHeader('Content-Length', len(resp)) request.write(resp) request.finish() def deferredError(self, err, format, request): err = "ERROR: (%s) %s" % (err.parents[-1], err.getErrorMessage()) request.setHeader('Content-Type', 'text/plain') request.setHeader('Content-Length', len(err)) request.write(err) request.finish() def deliverStaticContent(self, resourceRoot, requestPath, request): """Read and deliver the static data content directly. """ resourcePath = os.path.realpath('%s/%s' % (resourceRoot, '/'.join(requestPath))) resourcePath = resourcePath.replace('//','/') # resourceRoot = resourceRoot.replace('//','/') # os.path.realpath expands softlinks. If we did not do this for # resource root it may not match resourcePath. realResourceRoot = os.path.realpath(resourceRoot) if not resourcePath.startswith(realResourceRoot): request.setResponseCode(404) self.kernel.logger.debug("Relative path (%s|%s|%s) in request points outside of resource root" % (requestPath,resourcePath, resourceRoot)) request.write("Relative path points outside resource root") request.finish() return if not os.path.isfile(resourcePath): request.setResponseCode(404) self.kernel.logger.debug("Request for non-existent static content") request.write("Static content unavailable.") request.finish() return suffix = resourcePath[resourcePath.rfind('.'):] if suffix in binaryFileMimeTypes.keys(): openMode = 'rb' request.setHeader('Content-Type', binaryFileMimeTypes[suffix]) elif suffix in plainFileMimeTypes.keys(): openMode = 'rt' request.setHeader('Content-Type', plainFileMimeTypes[suffix]) else: openMode = 'rt' request.setHeader('Content-Type', 'text/html') try: res = open(resourcePath, openMode) fsize = os.stat(resourcePath)[6] FileTransfer(res, fsize, request) except Exception, ex: request.setResponseCode(404) request.write("Could not read resource %s: %s" % (resourcePath, str(ex))) self.kernel.logger.debug("Could not read static resource %s: %s" % (resourcePath, str(ex))) request.finish()
class PelotonClientAdapter(pb.Referenceable): """ Referenceable used by client to call methods on the PSC. """ def __init__(self, kernel, clientObj): self.kernel = kernel self.dispatcher = kernel.dispatcher self.routingTable = kernel.routingTable self.requestInterface = PelotonRequestInterface(kernel) self.logger = kernel.logger self.clientObj = clientObj self.eventHandlers=[] def remote_call(self, service, method, *args, **kwargs): """ Make a call to the specified service.method and return the result.""" return self.requestInterface.public_call(self.clientObj, 'raw', service, method, args, kwargs) def remote_post(self, service, method, *args, **kwargs): """ Put a call on the call queue for later execution. Do not return result to client; this call will execute regardless of what the client does subsequently. """ raise NotImplementedError def remote_postLater(self, delay_seconds, service, method, *args, **kwargs): """ Post call onto the call queue after a delay of delay_seconds. """ raise NotImplementedError def remote_postAt(self, dateTime, service, method, *args, **kwargs): """ Post call onto the call queue at some future time. """ raise NotImplementedError def remote_fireEvent(self, key, exchange='events', **kwargs): """ Fire an event onto the bus. """ self.dispatcher.fireEvent(key, exchange, **kwargs) def remote_register(self, key, handler, exchange='events'): """ Register to receive events with the given handler. Handler must be a Referenceable providing remote_eventReceived.""" handler = RemoteEventHandler(handler) self.eventHandlers.append(handler) self.dispatcher.register(key, handler, exchange) def remote_deregister(self, handler): """ De-register handler as a listener. """ for h in self.eventHandlers: if h.remoteHandler == handler: handler = h break else: # no handler registered self.logger.error("Attempt to de-register handler for event that is not registered.") return self.dispatcher.deregister(handler) self.eventHandlers.remove(handler) def remote_getPSCProfile(self, guid=None): """ Returns the serialised profile for the referenced PSC or self if guid is None. """ if not guid: return repr(self.kernel.profile) else: try: return repr(self.routingTable.pscByGUID[guid].profile) except KeyError: raise PelotonError("%s is unknown" % guid) def remote_getRegisteredExchanges(self): """ Return a list of event exchanges registered in the dispatcher. """ return self.dispatcher.getRegisteredExchanges()