[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pyamf-commits
Subject:    [pyamf-commits] r84 - branches/remoting-2/pyamf
From:       pyamf-commits () collab ! com (pyamf-commits () collab ! com)
Date:       2007-10-27 21:18:04
Message-ID: 20071027191755.A7AC37BC027 () mail ! collab ! com
[Download RAW message or body]

Author: nick
Date: 2007-10-27 21:17:55 +0200 (Sat, 27 Oct 2007)
New Revision: 84

Added:
   branches/remoting-2/pyamf/messaging.py
Removed:
   branches/remoting-2/pyamf/remoting.py
Modified:
   branches/remoting-2/pyamf/amf0.py
Log:
Moved Message* to own module

Modified: branches/remoting-2/pyamf/amf0.py
===================================================================
--- branches/remoting-2/pyamf/amf0.py	2007-10-26 22:34:15 UTC (rev 83)
+++ branches/remoting-2/pyamf/amf0.py	2007-10-27 19:17:55 UTC (rev 84)
@@ -261,7 +261,7 @@
         ((bool,), "writeBoolean"),
         ((int,long,float), "writeNumber"), # Maybe add decimal ?
         ((types.StringTypes,), "writeString"),
-        ((util.ET._ElementInterface,), "writeXML"),
+        ((util.ET.Element,), "writeXML"),
         ((types.DictType,), "writeMixedArray"),
         ((types.ListType,types.TupleType,), "writeArray"),
         ((datetime.date, datetime.datetime), "writeDate"),

Copied: branches/remoting-2/pyamf/messaging.py (from rev 83, \
branches/remoting-2/pyamf/remoting.py) \
                ===================================================================
--- branches/remoting-2/pyamf/messaging.py	                        (rev 0)
+++ branches/remoting-2/pyamf/messaging.py	2007-10-27 19:17:55 UTC (rev 84)
@@ -0,0 +1,261 @@
+# -*- encoding: utf8 -*-
+#
+# Copyright (c) 2007 The PyAMF Project. All rights reserved.
+# 
+# Arnar Birgisson
+# Thijs Triemstra
+# Nick Joyce
+# 
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+# 
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+# 
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+"""AMF Remoting support"""
+
+class AMFMessageDecoder(object):
+
+    def __init__(self, data):
+        self.input = util.BufferedByteStream(data)
+        self.msg = AMFMessage()
+
+    def decode(self):
+        # The first byte of the AMF file/stream is the AMF type.
+        self.msg.amfVersion = self.input.read_uchar()
+        if self.msg.amfVersion == GeneralTypes.AMF0:
+            parser_class = amf0.Parser
+        elif self.msg.amfVersion == GeneralTypes.AMF3:
+            from pyamf import amf3
+
+            parser_class = amf3.Parser
+        else:
+            raise Exception("Invalid AMF version: " + str(self.msg.amfVersion))
+        # The second byte is the client type.
+        self.msg.clientType = self.input.read_uchar()
+        # The third and fourth bytes form an integer value that specifies
+        # the number of headers.
+        header_count = self.input.read_short()
+        # Headers are used to request debugging information, send 
+        # authentication info, tag transactions, etc.
+        for i in range(header_count):
+            header = AMFMessageHeader()
+            # UTF string (including length bytes) - header name.
+            name_len = self.input.read_ushort()
+            header.name = self.input.read_utf8_string(name_len)
+            # Specifies if understanding the header is "required".
+            header.required = bool(self.input.read_uchar())
+            # Long - Length in bytes of header.
+            header.length = self.input.read_ulong()
+            # Variable - Actual self.input (including a type code).
+            header.data = parser_class(self.input).readElement()
+            self.msg.headers.append(header)
+        # Between the headers and the start of the bodies is a int 
+        # specifying the number of bodies.
+        bodies_count = self.input.read_short()
+        # A single AMF envelope can contain several requests/bodies; 
+        # AMF supports batching out of the box.
+        for i in range(bodies_count):
+            body = AMFMessageBody()
+            # The target may be one of the following:
+            # - An http or https URL. In that case the gateway should respond 
+            #   by sending a SOAP request to that URL with the specified data. 
+            #   In that case the data will be an Array and the first key 
+            #   (data[0]) contains the parameters to be sent.
+            # - A string with at least one period (.). The value to the right 
+            #   of the right-most period is the method to be called. The value 
+            #   to the left of that is the service to be invoked including package 
+            #   name. In that case data will be an Array of arguments to be sent 
+            #   to the method.
+            target_len = self.input.read_ushort()
+            body.target = self.input.read_utf8_string(target_len)
+            # The response is a string that gives the body an id so it can be 
+            # tracked by the client.
+            response_len = self.input.read_ushort()
+            body.response = self.input.read_utf8_string(response_len)
+            # Body length in bytes.            from pyamf import amf0
+
+            body.length = self.input.read_ulong()
+            # Actual data (including a type code).
+            body.data = parser_class(self.input).readElement()
+            # Bodies contain actual Remoting requests and responses.
+            self.msg.bodies.append(body)
+
+        return self.msg
+
+class AMFMessageEncoder:
+
+    def __init__(self, msg):
+        self.output = util.BufferedByteStream()
+        self.msg = msg
+
+    def encode(self):
+
+        encoder_class = amf0.Encoder
+        # Write AMF version.
+        self.output.write_uchar(self.msg.amfVersion)
+        # Client type.
+        self.output.write_uchar(self.msg.clientType)
+        # Header length.
+        header_count = len(self.msg.headers)
+        self.output.write_short(header_count)
+        # Write headers.
+        for header in self.msg.headers:
+            # Write header name.
+            self.output.write_utf8_string(header.name)
+            # Write header requirement.
+            self.output.write_uchar(header.required)
+            # Write length in bytes of header.
+            self.output.write_ulong(-1)
+            # Header data.
+            encoder_class(self.output).writeElement(header.data)
+        # Write bodies length.
+        bodies_count = len(self.msg.bodies)
+        self.output.write_short(bodies_count)
+        # Write bodies.
+        for body in self.msg.bodies:
+            # Target (/1/onResult).
+            self.output.write_utf8_string(body.target)
+            # Response (null).
+            self.output.write_utf8_string(body.response)
+            # Body length in bytes.
+            self.output.write_ulong(-1)
+            # Actual Python result data.
+            encoder_class(self.output).writeElement(body.data)
+
+        return self.output
+
+class AMFMessage:
+
+    def __init__(self):
+        self.amfVersion = GeneralTypes.AMF0
+        self.clientType = GeneralTypes.AC_Flash
+        self.headers = []
+        self.bodies = []
+
+    def __repr__(self):
+        r = "<AMFMessage amfVersion=" + str(self.amfVersion) + " clientType=" + \
str(self.clientType) + "\n" +        for h in self.headers:
+            r += "   " + repr(h) + "\n"
+        for b in self.bodies:
+            r += "   " + repr(b) + "\n"
+        r += ">"
+        return r
+
+class AMFMessageHeader:
+
+    def __init__(self):
+        self.name = None
+        self.required = None
+        self.length = None
+        self.data = None
+
+    def __repr__(self):
+        return "<AMFMessageHeader name=%s data=%r>" % (self.name, self.data)
+
+class AMFMessageBody:
+
+    def __init__(self):
+        self.target = None
+        self.response = None
+        self.length = None
+        self.data = None
+
+    def __repr__(self):
+        return "<AMFMessageBody target=%s data=%r>" % (self.target, self.data)
+
+class Server:
+    def __init__(self, data):
+        if data:
+            self.request = AMFMessageDecoder(data).decode()
+            self.response = AMFMessage()
+        else:
+            raise Exception("Invalid AMF request received")
+
+    def __repr__(self):
+        return "<Server request=%s response=%d>" % (self.request, self.response)
+
+    def setResponse(self, target, type, data):
+        """
+        Set a response based on a request you received through getRequests.
+        """
+        if type == GeneralTypes.REMOTING_RESULT:
+            target += '/onResult'
+
+        elif type == GeneralTypes.REMOTING_STATUS:
+            target += '/onStatus'
+
+        elif type == GeneralTypes.REMOTING_DEBUG:
+            target += '/onDebugEvents'
+
+        body = AMFMessageBody()
+        body.target = target
+        body.response = ''
+        body.data = data
+
+        return self.response.bodies.append(body)
+
+    def getResponse(self):
+        """
+        Get all responses for the client. Call this after you answered all
+        the requests with setResponse.
+        """
+        self.response.clientType = self.request.clientType
+        data = AMFMessageEncoder(self.response).encode()
+        return data
+
+    def addHeader(self, name, required, data):
+            """
+            Add a header to the server response.
+            """
+            self.response.addHeader(name, required, data)
+
+    def getRequests(self):
+        """
+        Returns the requests that are made to the gateway.
+        """
+        return self.request.bodies
+    
+    def getHeaders(self):
+        """
+        Returns the request headers.
+        """
+        return self.request.headers
+
+class Client:
+    def __init__(self):
+        self.request = AMFMessage()
+        self.response = AMFMessage()
+
+    def __repr__(self):
+        return "<Client endpoint=%s>" % (self.endpoint)
+
+    def setRequest(self, servicePath, data):
+        """
+        setRequest creates the encoded AMF request for the server. It expects  
+        the servicepath and methodname, and the parameters of the methodcall.
+        """
+        body = AMFMessageBody()
+        body.target = servicePath
+        body.response = '/1'
+        body.data = data
+        self.request.bodies.append(body)
+        data = AMFMessageEncoder(self.request).encode()
+        return data.getvalue()
+
+    def getResponse(self, data):
+        self.response = AMFMessageDecoder(data).decode()
+        return self.response.bodies

Deleted: branches/remoting-2/pyamf/remoting.py


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic