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