Package pyamf :: Package remoting :: Module amf3 |
[hide private]
[frames] | no frames]

# Source Code for Module pyamf.remoting.amf3

      1  # Copyright (c) 2007-2009 The PyAMF Project.
      2  # See LICENSE.txt for details.
      3
      4  """
      5  AMF3 RemoteObject support.
      6
      7  @see: U{RemoteObject on LiveDocs
      8  <http://livedocs.adobe.com/flex/3/langref/mx/rpc/remoting/RemoteObject.html>}
      9
     10  @since: 0.1.0
     11  """
     12
     13  import calendar
     14  import time
     15  import uuid
     16  import sys
     17
     18  import pyamf
     19  from pyamf import remoting
     20  from pyamf.flex import messaging
     21
     22
     23 -class BaseServerError(pyamf.BaseError):
     24      """
     25      Base server error.
     26      """
     27
     28
     29 -class ServerCallFailed(BaseServerError):
     30      """
     31      A catchall error.
     32      """
     33      _amf_code = 'Server.Call.Failed'
     34
     35
     36 -def generate_random_id():
     37      return str(uuid.uuid4())
     38
     39
     40 -def generate_acknowledgement(request=None):
     41      ack = messaging.AcknowledgeMessage()
     42
     43      ack.messageId = generate_random_id()
     44      ack.clientId = generate_random_id()
     45      ack.timestamp = calendar.timegm(time.gmtime())
     46
     47      if request:
     48          ack.correlationId = request.messageId
     49
     50      return ack
     51
     52
     53 -def generate_error(request, cls, e, tb, include_traceback=False):
     54      """
     55      Builds an L{ErrorMessage<pyamf.flex.messaging.ErrorMessage>} based on the
     56      last traceback and the request that was sent.
     57      """
     58      import traceback
     59
     60      if hasattr(cls, '_amf_code'):
     61          code = cls._amf_code
     62      else:
     63          code = cls.__name__
     64
     65      detail = ''
     66      rootCause = None
     67
     68      if include_traceback:
     69          detail = []
     70          rootCause = e
     71
     72          for x in traceback.format_exception(cls, e, tb):
     73              detail.append(x.replace("\\n", ''))
     74
     75      return messaging.ErrorMessage(messageId=generate_random_id(),
     76          clientId=generate_random_id(), timestamp=calendar.timegm(time.gmtime()),
     77          correlationId = request.messageId, faultCode=code, faultString=str(e),
     78          faultDetail=str(detail), extendedData=detail, rootCause=rootCause)
     79
     80
     81 -class RequestProcessor(object):
     82 -    def __init__(self, gateway):
     83          self.gateway = gateway
     84
     85 -    def buildErrorResponse(self, request, error=None):
     86          """
     87          Builds an error response.
     88
     89          @param request: The AMF request
     90          @type request: L{Request<pyamf.remoting.Request>}
     91          @return: The AMF response
     92          @rtype: L{Response<pyamf.remoting.Response>}
     93          """
     94          if error is not None:
     95              cls, e, tb = error
     96          else:
     97              cls, e, tb = sys.exc_info()
     98
     99          return generate_error(request, cls, e, tb, self.gateway.debug)
    100
    101 -    def _getBody(self, amf_request, ro_request, **kwargs):
    102          """
    103          @raise ServerCallFailed: Unknown request.
    104          """
    105          if isinstance(ro_request, messaging.CommandMessage):
    106              return self._processCommandMessage(amf_request, ro_request, **kwargs)
    107          elif isinstance(ro_request, messaging.RemotingMessage):
    108              return self._processRemotingMessage(amf_request, ro_request, **kwargs)
    109          elif isinstance(ro_request, messaging.AsyncMessage):
    110              return self._processAsyncMessage(amf_request, ro_request, **kwargs)
    111          else:
    112              raise ServerCallFailed("Unknown request: %s" % ro_request)
    113
    114 -    def _processCommandMessage(self, amf_request, ro_request, **kwargs):
    115          """
    116          @raise ServerCallFailed: Unknown Command operation.
    117          @raise ServerCallFailed: Authorization is not supported in RemoteObject.
    118          """
    119          ro_response = generate_acknowledgement(ro_request)
    120
    121          if ro_request.operation == messaging.CommandMessage.PING_OPERATION:
    122              ro_response.body = True
    123
    124              return remoting.Response(ro_response)
    125          elif ro_request.operation == messaging.CommandMessage.LOGIN_OPERATION:
    126              raise ServerCallFailed("Authorization is not supported in RemoteObject")
    127          elif ro_request.operation == messaging.CommandMessage.DISCONNECT_OPERATION:
    128              return remoting.Response(ro_response)
    129          else:
    130              raise ServerCallFailed("Unknown Command operation %s" % ro_request.operation)
    131
    132 -    def _processAsyncMessage(self, amf_request, ro_request, **kwargs):
    133          ro_response = generate_acknowledgement(ro_request)
    134          ro_response.body = True
    135
    136          return remoting.Response(ro_response)
    137
    138 -    def _processRemotingMessage(self, amf_request, ro_request, **kwargs):
    139          ro_response = generate_acknowledgement(ro_request)
    140
    141          service_name = ro_request.operation
    142
    143          if hasattr(ro_request, 'destination') and ro_request.destination:
    144              service_name = '%s.%s' % (ro_request.destination, service_name)
    145
    146          service_request = self.gateway.getServiceRequest(amf_request,
    147                                                           service_name)
    148
    149          # fire the preprocessor (if there is one)
    150          self.gateway.preprocessRequest(service_request, *ro_request.body,
    151                                         **kwargs)
    152
    153          ro_response.body = self.gateway.callServiceRequest(service_request,
    154                                                  *ro_request.body, **kwargs)
    155
    156          return remoting.Response(ro_response)
    157
    158 -    def __call__(self, amf_request, **kwargs):
    159          """
    160          Processes an AMF3 Remote Object request.
    161
    162          @param amf_request: The request to be processed.
    163          @type amf_request: L{Request<pyamf.remoting.Request>}
    164
    165          @return: The response to the request.
    166          @rtype: L{Response<pyamf.remoting.Response>}
    167          """
    168          ro_request = amf_request.body[0]
    169
    170          try:
    171              return self._getBody(amf_request, ro_request, **kwargs)
    172          except (KeyboardInterrupt, SystemExit):
    173              raise
    174          except:
    175              return remoting.Response(self.buildErrorResponse(ro_request),
    176                                       status=remoting.STATUS_ERROR)
    177