"""Simple example comet server for educational purposes. Requires Spawning and Eventlet http://pypi.python.org/pypi/eventlet/ http://pypi.python.org/pypi/Spawning/ Run the comet server with: spawn spawningcomet.wsgi_application --threads=0 Then, to send an event to any browsers waiting, run this in another terminal: python spawningcomet.py hello world """ import struct import sys import uuid from eventlet import api from eventlet import coros SEND_EVENT_INTERFACE = '' SEND_EVENT_PORT = 4200 HTML_TEMPLATE = """

Dynamic content will appear below

""" class Comet(object): def __init__(self): api.spawn( api.tcp_server, api.tcp_listener((SEND_EVENT_INTERFACE, SEND_EVENT_PORT)), self.read_events_forever) self.current_event = {'event': coros.event(), 'next': None} self.first_event_id = str(uuid.uuid1()) self.events = {self.first_event_id: self.current_event} def read_events_forever(self, (sock, addr)): reader = sock.makefile('r') try: while True: ## Read the next event value out of the socket valuelen = reader.read(4) if not valuelen: break valuelen, = struct.unpack('!L', valuelen) value = reader.read(valuelen) ## Make a new event and link the current event to it old_event = self.current_event old_event['next'] = str(uuid.uuid1()) self.current_event = { 'event': coros.event(), 'next': None} self.events[old_event['next']] = self.current_event ## Send the event value to any waiting http requests old_event['event'].send(value) finally: reader.close() sock.close() def __call__(self, env, start_response): if env['REQUEST_METHOD'] != 'GET': start_response('405 Method Not Allowed', [('Content-type', 'text/plain')]) return ['Method Not Allowed\n'] if not env['PATH_INFO'] or env['PATH_INFO'] == '/': start_response('200 OK', [('Content-type', 'text/html')]) return HTML_TEMPLATE % (self.first_event_id, ) event = self.events.get(env['PATH_INFO'][1:], None) if event is None: start_response('404 Not Found', [('Content-type', 'text/plain')]) return ['Not Found\n'] value = event['event'].wait() start_response('200 OK', [ ('Content-type', 'text/plain'), ('X-Next-Event', event['next'])]) return [value, '\n'] def send_event(where, value): sock = api.connect_tcp(where) writer = sock.makefile('w') writer.write('%s%s' % (struct.pack('!L', len(value)), value)) if __name__ == '__main__': if len(sys.argv) > 1: value = ' '.join(sys.argv[1:]) else: value = sys.stdin.read() send_event((SEND_EVENT_INTERFACE, SEND_EVENT_PORT), value) else: wsgi_application = Comet()