Source code for paradrop.backend.pdfcd.apiinternal

from twisted.web import xmlrpc
from twisted.internet import defer, utils
from pdtools.coms.client import RpcClient

from pdtools.lib.output import out
from pdtools.lib import store, riffle, names

from pdtools.lib import nexus

# HOST = 'localhost'
HOST = 'paradrop.io'

###############################################################################
# New Riffle Additions
###############################################################################


[docs]class ServerPerspective(riffle.RifflePerspective):
[docs] def initialize(self): # The function target that subscribes to output events self.subscribed = None
[docs] def destroy(self): # Remove the log subscriber when the connection goes down. if self.subscribed is not None: out.removeSubscriber(self.subscribed)
@defer.inlineCallbacks
[docs] def perspective_subscribeLogs(self, target): ''' Fetch all logs since the target time. Stream all new logs to the server as they come in. ''' # Adds the target function (newLogs) to out's streaming subscription set # Do not do this without the user's consent out.addSubscriber(self.remote.newLogs) self.subscribed = self.remote.newLogs logs = yield out.getLogsSince(target) defer.returnValue(logs)
[docs]class ToolsPerspective(riffle.RifflePerspective): pass
[docs]def pollServer(host): ''' Poll the server for a connection. ''' def success(a): print 'Connected to server!' riffle.portal.pollConnect(success, host=host)
[docs]def checkStartRiffle(): ''' Temporary function. Do not start serving or connecting over riffle until we have our keys (which occurs during currently optional provisioning) ''' if not riffle.portal.certCa: out.warn("Cannot start riffle server, no CA certificate found") return out.info('Received certs, opening riffle portal') # Check to make sure we are not already listening # as of this writing we are not checking for previously-provisioned state) # Open connection to the server from twisted.internet import reactor reactor.callLater(.1, riffle.portal.connect, HOST)
############################################################################### # Old ############################################################################### @defer.inlineCallbacks
[docs]def api_provision(pdid, key, cert): ''' Provision this router with an id and a set of keys. This is a temporary call until the provisioning process is finalized. ''' # SO TEMP IT HURTS: # yield # ret = {'root': nexus.core.rootPath, 'logs': nexus.core.logPath} # defer.returnValue(ret) # temp: check to make sure we're not already provisioned. Do not allow for # multiple provisioning. This is a little hacky-- better to move this into store if riffle.portal.certCa: raise ValueError("This device is already provisioned as " + nexus.core.get('pdid')) nexus.core.set('pdid', pdid) nexus.core.saveKey(key, 'pub') nexus.core.saveKey(cert, 'ca') riffle.portal.keyPrivate = key riffle.portal.certCa = cert # If we are being provisioned for the first time, start riffle services yield checkStartRiffle() nexus.core.connect() # TEMP # logs = yield out.getLogsSince(0) # defer.returnValue(logs) # Return success to the user defer.returnValue('Done!')
############################################################################### # Temporary-- this needs a home, haven't decided where yet. ###############################################################################
[docs]class Base(xmlrpc.XMLRPC): def __init__(self, module, **kwargs): xmlrpc.XMLRPC.__init__(self, kwargs) # build a dict of exposed api methods self.apiFunctions = {k.replace('api_', ''): apiWrapper(getattr(module, k)) for k in dir(module) if 'api_' in k}
[docs] def lookupProcedure(self, procedurePath): try: return self.apiFunctions[procedurePath] except KeyError: raise xmlrpc.NoSuchFunction(self.NOT_FOUND, "procedure %s not found" % procedurePath)
[docs]def castFailure(failure): ''' Converts an exception (or general failure) into an xmlrpc fault for transmission. ''' out.info("Failed API call (TODO: categorize errors)") raise xmlrpc.Fault(123, failure.getErrorMessage())
[docs]def apiWrapper(target): ''' Add a final line of error and success callbacks before going onto the wire''' def outside(*args): return target(*args).addErrback(castFailure).addCallback(castSuccess) return outside
[docs]def castSuccess(res): out.info("Completed API call (TODO: add details)") # screen out Objectids on mongo returns. The remote objects have no # need for them, and they confuse xmlrpc if isinstance(res, dict): res.pop('_id', None) return res