Hi,

I'm trying to get browsers to communicate with an AMP API. Right now I'm trying 
to do that using WebSockets with Corbin SImpson's txWS. Eventually I'll try to 
write a Twisted implementation of SockJS, which is basically portable 
websockets all the way down to IE6.

The issue is that while AMP is inherently a binary protocol, WebSockets 
transfer text (well, that's a lie: there's a binary version, but it's even less 
widely supported than WebSockets themselves -- and SockJS doesn't support it at 
all, although it's on the roadmap). So, I need an alternative, preferably 
7-bit, serialization for AMP boxes.

My first attempt at that serialization is JSON -- widely supported in browsers, 
and should map pretty closely to what AMP can do:

  - AMPLIsts are objects
  - ListOfs are arrays
  - numeric types and strings are more or less natively supported (except JSON 
is always text, never bytes)
  - booleans are booleans

Right now I have something that almost works, but is really a crude, cheap, 
untested hack. I'm wondering if there's a better integration point.

"""
AMP over WebSockets support.
"""
import json
import txws

from twisted.internet import defer, protocol
from twisted.python import log


class Bridge(protocol.Protocol):
    """
    Two-way AMP over WebSockets bridge.
    """
    def __init__(self, amp):
        self._amp = amp
        amp.startReceivingBoxes(self)
        amp.boxSender = self


    def sendBox(self, box):
        """
        Sends a box over the WebSocket as JSON.
        """
        log.msg("Sending box: {}".format(box))
        self.transport.write(json.dumps(box))


    def jsonObjectReceived(self, obj):
        """
        Hands the JSON object (dict) over to ampBoxReceived.
        """
        log.msg("JSON object received: {}".format(obj))
        self._amp.boxReceiver.ampBoxReceived(obj)


    def dataReceived(self, data):
        """
        Calls jsonObjectReceived.

        This assumes that JSON objects will always arrive as 1 chunk.
        """
        self.jsonObjectReceived(json.loads(data))



class BridgeFactory(protocol.Factory):
    """
    A factory for AMP over WebSockets bridges.
    """
    def __init__(self, ampFactory):
        self._ampFactory = ampFactory


    def buildProtocol(self, addr):
        """
        Builds a bridge and associates it with an AMP protocol instance.
        """
        return Bridge(self._ampFactory.buildProtocol(addr))



def makeFactory(ampFactory):
    """
    Makes a WebSocket factory that bridges AMP messages.
    """
    return txws.WebSocketFactory(BridgeFactory(ampFactory))


An issue I'm running into is an AMP ListOf. With the above code, ListOf still 
gets translated to a string, and obviously I want it to be a list. When that 
ListOf has actual data in it, I get the binary representation.

The other issues that I predict will happen but haven't ran into yet (because I 
don't use that functionality) are:
    - booleans -- expects "True" or "False" but gets True or False (true and 
false in JSON) -- can be fixed both on the client and the server side, not sure 
where the optimal place would be
    - AMPList -- same reason as ListOf

ints, floats… will magically work, but it's a bit ugly: the only reason it 
works is that the factory for them is int and float, and, well, int(5) == 5 == 
int("5"), so it doesn't actually matter if it's already an int or a str.

In my Command implementation, I'm returning {"k": anAxiomQuery} -- so it's 
iterable but not a list. I can write a custom JSON encoder that can take 
arbitrary iterables, of course.

cheers
lvh




_______________________________________________
Twisted-Python mailing list
Twisted-Python@twistedmatrix.com
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python

Reply via email to