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
[email protected]
http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python