# HG changeset patch # User drewp@bigasterisk.com # Date 1555998887 25200 # Node ID 576ee2e2b2a2c54f7ecf7ad0d3ec0522b71c3e5c # Parent b1337ad3ec2d5b47c051db838817f45a11130142 twisted_sse moves to its own git repo Ignore-this: f82e34ec726c8b912de439e371f8debf diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/.gitignore --- a/lib/twisted_sse/.gitignore Mon Apr 22 21:58:09 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -*.pyc diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/MANIFEST.in --- a/lib/twisted_sse/MANIFEST.in Mon Apr 22 21:58:09 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2 +0,0 @@ -include *.py -include README.md \ No newline at end of file diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/README.md --- a/lib/twisted_sse/README.md Mon Apr 22 21:58:09 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ - -This is https://github.com/juggernaut/twisted-sse-demo with some -changes, including: - -- rename from twisted-sse-demo to twisted_sse so it can be a package -- add setup.py so it can be depended on -- some python3 support -- remove crochet - -api_example.py is probably out of date. - -drewp is using cyclone.sse for server support and this -twisted_sse.eventsource as the client. diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/__init__.py diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/api_example.py --- a/lib/twisted_sse/api_example.py Mon Apr 22 21:58:09 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,13 +0,0 @@ -import time - -from eventsource import EventSource - -EVENTSOURCE_URL = 'http://localhost:12000/subscribe' - -def onmessage(data): - print('Got payload with data %s' % data) - -if __name__ == '__main__': - eventSource = EventSource(EVENTSOURCE_URL) - eventSource.onmessage(onmessage, callInThread=True) - time.sleep(20) diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/eventsource.py --- a/lib/twisted_sse/eventsource.py Mon Apr 22 21:58:09 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -from twisted.internet import reactor -from twisted.internet.defer import Deferred -from twisted.web.client import Agent -from twisted.web.http_headers import Headers - -from .sse_client import EventSourceProtocol - - -class EventSource(object): - """ - The main EventSource class - """ - def __init__(self, url, userAgent): - # type: (str, bytes) - self.url = url - self.userAgent = userAgent - self.protocol = EventSourceProtocol(self.onConnectionLost) - self.errorHandler = None - self.stashedError = None - self.connect() - - def connect(self): - """ - Connect to the event source URL - """ - agent = Agent(reactor, connectTimeout=5) - self.agent = agent - d = agent.request( - b'GET', - self.url, - Headers({ - b'User-Agent': [self.userAgent], - b'Cache-Control': [b'no-cache'], - b'Accept': [b'text/event-stream; charset=utf-8'], - }), - None) - d.addCallbacks(self.cbRequest, self.connectError) - - def cbRequest(self, response): - if response is None: - # seems out of spec, according to https://twistedmatrix.com/documents/current/api/twisted.web.iweb.IAgent.html - raise ValueError('no response for url %r' % self.url) - elif response.code != 200: - self.callErrorHandler("non 200 response received: %d" % - response.code) - else: - response.deliverBody(self.protocol) - - def connectError(self, ignored): - self.callErrorHandler("error connecting to endpoint: %s" % self.url) - - def onConnectionLost(self, reason): - # overridden - reason.printDetailedTraceback() - - def callErrorHandler(self, msg): - if self.errorHandler: - func, callInThread = self.errorHandler - if callInThread: - reactor.callInThread(func, msg) - else: - func(msg) - else: - self.stashedError = msg - - def onerror(self, func, callInThread=False): - self.errorHandler = func, callInThread - if self.stashedError: - self.callErrorHandler(self.stashedError) - - def onmessage(self, func, callInThread=False): - self.addEventListener('message', func, callInThread) - - def addEventListener(self, event, func, callInThread=False): - assert isinstance(event, bytes), event - callback = func - if callInThread: - callback = lambda data: reactor.callInThread(func, data) - self.protocol.addCallback(event, callback) diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/setup.py --- a/lib/twisted_sse/setup.py Mon Apr 22 21:58:09 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,12 +0,0 @@ -from distutils.core import setup - -setup( - name='twisted_sse', - version='0.2.0', - packages=['twisted_sse'], - package_dir={'twisted_sse': ''}, - install_requires=['twisted'], - url='https://projects.bigasterisk.com/', - author='Drew Perttula', - author_email='drewp@bigasterisk.com', - ) diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/sse_client.py --- a/lib/twisted_sse/sse_client.py Mon Apr 22 21:58:09 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -from twisted.protocols.basic import LineReceiver - - -class EventSourceProtocol(LineReceiver): - def __init__(self, onConnectionLost): - self.onConnectionLost = onConnectionLost - self.delimiter = b'\n' - self.MAX_LENGTH = 1 << 20 - self.callbacks = {} - self.finished = None - # Initialize the event and data buffers - self.event = b'message' - self.data = b'' - - def lineLengthExceeded(self, line): - raise NotImplementedError('line too long') - - def setFinishedDeferred(self, d): - self.finished = d - - def addCallback(self, event, func): - self.callbacks[event] = func - - def lineReceived(self, line): - if line == b'': - # Dispatch event - self.dispatchEvent() - else: - try: - field, value = line.split(b':', 1) - # If value starts with a space, strip it. - value = lstrip(value) - except ValueError: - # We got a line with no colon, treat it as a field(ignore) - return - - if field == b'': - # This is a comment; ignore - pass - elif field == b'data': - self.data += value + b'\n' - elif field == b'event': - self.event = value - elif field == b'id': - # Not implemented - pass - elif field == b'retry': - # Not implemented - pass - - def connectionLost(self, reason): - self.onConnectionLost(reason) - - def dispatchEvent(self): - """ - Dispatch the event - """ - # If last character is LF, strip it. - if self.data.endswith(b'\n'): - self.data = self.data[:-1] - if self.event in self.callbacks: - self.callbacks[self.event](self.data) - self.data = b'' - self.event = b'message' - -def lstrip(value): - return value[1:] if value.startswith(b' ') else value diff -r b1337ad3ec2d -r 576ee2e2b2a2 lib/twisted_sse/sse_server.py --- a/lib/twisted_sse/sse_server.py Mon Apr 22 21:58:09 2019 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -import sys - -from twisted.web import server, resource -from twisted.internet import reactor -from twisted.python import log - - -class Root(resource.Resource): - """ - Root resource; serves JavaScript - """ - def getChild(self, name, request): - if name == '': - return self - return resource.Resource.getChild(self, name, request) - - def render_GET(self, request): - return r""" - -
- - - -