Skip to content

Commit

Permalink
Adds a lib for server sent events. bump version.
Browse files Browse the repository at this point in the history
  • Loading branch information
byteface committed Feb 25, 2022
1 parent 24d744f commit f129b8b
Show file tree
Hide file tree
Showing 2 changed files with 156 additions and 0 deletions.
5 changes: 5 additions & 0 deletions domonic/webapi/messaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""
domonic.webapi.messaging
====================================
https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API
"""
151 changes: 151 additions & 0 deletions domonic/webapi/sse.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
"""
domonic.webapi.sse
====================================
https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
TODO - consider a blocking verison?
TODO - port one of the polyfills?
https://github.com/EventSource/eventsource/blob/master/lib/eventsource.js
https://github.com/remy/polyfills/blob/master/EventSource.js
https://github.com/Yaffle/EventSource/blob/master/src/eventsource.js
# TESTING - useage example... clone this and point at the stream
# https://github.com/byteface/SSELoggerDemo
"""

from domonic.events import MessageEvent, EventTarget


class EventSource(EventTarget):
# https://developer.mozilla.org/en-US/docs/Web/API/EventSource

CONNECTING = 0
OPEN = 1
CLOSED = 2

def __init__(self, url, eventSourceInitDict=None, **kwargs):
"""
The EventSource interface provides the ability to asynchronously receive messages from a server using simple push paradigm.
"""
eventSourceInitDict = eventSourceInitDict or kwargs
super().__init__()
self._url = url
self._readyState = EventSource.CLOSED
self._withCredentials = eventSourceInitDict.get('withCredentials', False)
self._lastEventId = eventSourceInitDict.get('lastEventId', None)

self._onmessage = eventSourceInitDict.get('onmessage', None)
self._onerror = eventSourceInitDict.get('onerror', None)
self._onopen = eventSourceInitDict.get('onopen', None)
self._onreadystatechange = eventSourceInitDict.get('onreadystatechange', None)

# from sseclient import SSEClient
# messages = SSEClient(url)
# self._readyState = EventSource.OPEN
# for msg in messages:
# self.onmessage(MessageEvent(msg))
# print(msg)
# self._readyState = EventSource.CLOSED

def _do_stuff():
from sseclient import SSEClient
messages = SSEClient(url)
self._readyState = EventSource.OPEN
# self.onopen(MessageEvent(messages))
for msg in messages:
self.onmessage(MessageEvent(msg))
# print(msg)
self._readyState = EventSource.CLOSED

# TODO - use a thread or it will block the main thread
import threading

# def _on_message(msg):
# self.onmessage(MessageEvent(msg))
# print(msg)
# self._readyState = EventSource.OPEN

# def _on_error(err):
# self.onerror(err)
# self._readyState = EventSource.CLOSED

# def _on_open(msg):
# self.onopen(msg)
# self._readyState = EventSource.OPEN

# def _on_ready_state_change(msg):
# self.onreadystatechange(msg)
# self._readyState = EventSource.OPEN

# def _on_close(msg):
# self.onclose(msg)
# self._readyState = EventSource.CLOSED

self._thread = threading.Thread(target=_do_stuff)
self._thread.start()

# print('this is so cool!')

@property
def readyState(self):
""" A number representing the state of the connection.
Possible values are CONNECTING (0), OPEN (1), or CLOSED (2). """
return self._readyState

@property
def url(self):
""" A DOMString representing the URL of the source. """
return self._url

@property
def withCredentials(self):
""" A boolean value indicating whether the EventSource object was
instantiated with cross-origin (CORS) credentials
set (true), or not (false, the default). """
return self._withCredentials

def close(self):
""" Closes the connection to the EventSource. """
self._readyState = EventSource.CLOSED
# close the thread
self._thread.join()
self._thread = None

def onreadystatechange(self, event):
""" Called when the state of the connection changes. """
pass

def onmessage(self, event):
""" Called when a message is received. """
if self._onmessage is not None:
self._onmessage(event)

def onerror(self, event):
""" Called when an error occurs. """
pass

def onopen(self, event):
""" Called when the connection is established. """
pass

# '''
# NOTE - if we write custom one rather than use lib...
# def _poll(self):

# if self._readyState == EventSource.CLOSED:
# return

# url = 'http://domain.com/events'
# headers = {
# 'Accept': 'text/event-stream',
# 'Cache-Control': 'no-cache',
# 'X-requested-with': 'XMLHttpRequest'
# }
# if self._lastEventId != None:
# headers['Last-Event-ID'] = self._lastEventId

# import requests
# response = requests.get(url, stream=True, headers=headers)
# # TODO - parse repsonse
# '''

0 comments on commit f129b8b

Please sign in to comment.