import other.json as json import os, os.path, logging log = logging.getLogger(os.path.basename(__file__)) import sys import uuid import re import urllib class Transport(): callback = 'c' domain = None headers = { 'Cache-Control': 'no-cache', 'Content-Type': 'text/plain; charset=UTF-8', } name = None def __init__(self, name, callback='c', domain=''): self.name = name self.callback = ''.join(re.findall('[a-z0-9_]+', callback)) self.domain = ''.join(re.findall('[a-z0-9._-]+', domain)) def start(self): return '' def write(self, data): return '''%s\r\n''' % (data) def get_headers(self): return self.headers.items() class LongPoll(Transport): def __init__(self, *args, **kwargs): self.headers['Content-Type'] = 'application/x-orbited-event-stream; charset=utf-8' Transport.__init__(self, *args, **kwargs) def start(self): return '' def write(self, data): return '''%s''' % (data) class BasicTransport(Transport): def __init__(self, *args, **kwargs): self.headers['Content-Type'] = 'text/html; charset=UTF-8' Transport.__init__(self, *args, **kwargs) def start(self): return '''\n''' def write(self, data): return '%s
\r\n' % (data,) class IFrameTransport(Transport): def __init__(self, *args, **kwargs): self.headers['Content-Type'] = 'text/html; charset=utf-8' self.headers['Refresh'] = '3000' Transport.__init__(self, *args, **kwargs) self.alert = "try{comet_log('iframe: ' + e.message + ' ' + e);}catch(e){}" initial_data = ''' ''' + ('' * 80) def start(self): return self.initial_data % {'callback':self.callback, 'domain':self.domain, 'alert':self.alert} def write(self, data): return '''\r\n''' % \ (self.callback, json.write(data), self.alert) class SSETransport(Transport): def __init__(self, *args, **kwargs): self.headers['Reconnection-Time'] = '2000' self.headers['Refresh'] = '3000' self.headers['Content-Type'] = 'application/x-dom-event-stream; charset=UTF-8' self.headers['Cache-Control'] = 'no-cache, must-revalidate' Transport.__init__(self, *args, **kwargs) def start(self): return 'Event: sessionid\ndata: %s\n\n' % (str(uuid.uuid4()).replace('-','')[:22],) def write(self, data): return 'Event: payload\n' + \ 'data: %s' % urllib.quote(data) + \ '\n\n' class XHRStreamTransport(Transport): boundary = '\r\n|O|\r\n' def __init__(self, *args, **kwargs): self.headers['Content-Type'] = 'application/x-orbited-event-stream; charset=utf-8' Transport.__init__(self, *args, **kwargs) initial_data = '.'*256 + '\r\n\r\n' def start(self): return self.initial_data def write(self, data): return data + self.boundary # if transport == 'xhr': ## application/xml based on: http://lists.macosforge.org/pipermail/webkit-dev/2007-June/002041.html ## must be some message here, at least one byte long... def format_block(s): ''' Formatter for block strings to be sent as HTTP. (so they can be written cleanly in python classes) Dedent every line of a string by the indent of the first line, replace newlines with '\r\n', and remove any trailing whitespace. ''' s = s.lstrip('\r\n').rstrip() # leading empty lines, trailing whitespace lines = s.expandtabs(4).splitlines() # find w, the smallest indent of a line with content w = min([len(line) - len(line.lstrip()) for line in lines]) return '\r\n'.join([line[w:] for line in lines]) class XHRMultipartTransport(Transport): boundary = 'orbited--' multipart_content_type = 'application/json' def __init__(self, *args, **kwargs): self.headers['Content-Type'] = 'multipart/x-mixed-replace;boundary="%s"' % boundary Transport.__init__(self, *args, **kwargs) def encode(self, data): boundary = "\r\n--%s\r\n" % self.boundary headers = (formatBlock(''' Content-type: %s Content-length: %s ''') + '\r\n\r\n') % (self.multipart_content_type, len(data)) return ''.join([headers, data, boundary]) transports = { 'basic': BasicTransport, 'longpoll': LongPoll, 'iframe': IFrameTransport, 'htmlfile': IFrameTransport, 'server_sent_events': SSETransport, 'sse': SSETransport, 'xhr_multipart': XHRMultipartTransport, 'xhr_stream': XHRStreamTransport, 'xhrstream': XHRStreamTransport, 'xhr': XHRStreamTransport, } def get_transport(name, *args, **kwargs): if name not in transports: return None return transports[name](name, *args, **kwargs)