Skip to content

Commit f129b8b

Browse files
committed
Adds a lib for server sent events. bump version.
1 parent 24d744f commit f129b8b

File tree

2 files changed

+156
-0
lines changed

2 files changed

+156
-0
lines changed

domonic/webapi/messaging.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
"""
2+
domonic.webapi.messaging
3+
====================================
4+
https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API
5+
"""

domonic/webapi/sse.py

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
"""
2+
domonic.webapi.sse
3+
====================================
4+
https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events
5+
6+
TODO - consider a blocking verison?
7+
TODO - port one of the polyfills?
8+
https://github.com/EventSource/eventsource/blob/master/lib/eventsource.js
9+
https://github.com/remy/polyfills/blob/master/EventSource.js
10+
https://github.com/Yaffle/EventSource/blob/master/src/eventsource.js
11+
12+
# TESTING - useage example... clone this and point at the stream
13+
# https://github.com/byteface/SSELoggerDemo
14+
15+
"""
16+
17+
from domonic.events import MessageEvent, EventTarget
18+
19+
20+
class EventSource(EventTarget):
21+
# https://developer.mozilla.org/en-US/docs/Web/API/EventSource
22+
23+
CONNECTING = 0
24+
OPEN = 1
25+
CLOSED = 2
26+
27+
def __init__(self, url, eventSourceInitDict=None, **kwargs):
28+
"""
29+
The EventSource interface provides the ability to asynchronously receive messages from a server using simple push paradigm.
30+
"""
31+
eventSourceInitDict = eventSourceInitDict or kwargs
32+
super().__init__()
33+
self._url = url
34+
self._readyState = EventSource.CLOSED
35+
self._withCredentials = eventSourceInitDict.get('withCredentials', False)
36+
self._lastEventId = eventSourceInitDict.get('lastEventId', None)
37+
38+
self._onmessage = eventSourceInitDict.get('onmessage', None)
39+
self._onerror = eventSourceInitDict.get('onerror', None)
40+
self._onopen = eventSourceInitDict.get('onopen', None)
41+
self._onreadystatechange = eventSourceInitDict.get('onreadystatechange', None)
42+
43+
# from sseclient import SSEClient
44+
# messages = SSEClient(url)
45+
# self._readyState = EventSource.OPEN
46+
# for msg in messages:
47+
# self.onmessage(MessageEvent(msg))
48+
# print(msg)
49+
# self._readyState = EventSource.CLOSED
50+
51+
def _do_stuff():
52+
from sseclient import SSEClient
53+
messages = SSEClient(url)
54+
self._readyState = EventSource.OPEN
55+
# self.onopen(MessageEvent(messages))
56+
for msg in messages:
57+
self.onmessage(MessageEvent(msg))
58+
# print(msg)
59+
self._readyState = EventSource.CLOSED
60+
61+
# TODO - use a thread or it will block the main thread
62+
import threading
63+
64+
# def _on_message(msg):
65+
# self.onmessage(MessageEvent(msg))
66+
# print(msg)
67+
# self._readyState = EventSource.OPEN
68+
69+
# def _on_error(err):
70+
# self.onerror(err)
71+
# self._readyState = EventSource.CLOSED
72+
73+
# def _on_open(msg):
74+
# self.onopen(msg)
75+
# self._readyState = EventSource.OPEN
76+
77+
# def _on_ready_state_change(msg):
78+
# self.onreadystatechange(msg)
79+
# self._readyState = EventSource.OPEN
80+
81+
# def _on_close(msg):
82+
# self.onclose(msg)
83+
# self._readyState = EventSource.CLOSED
84+
85+
self._thread = threading.Thread(target=_do_stuff)
86+
self._thread.start()
87+
88+
# print('this is so cool!')
89+
90+
@property
91+
def readyState(self):
92+
""" A number representing the state of the connection.
93+
Possible values are CONNECTING (0), OPEN (1), or CLOSED (2). """
94+
return self._readyState
95+
96+
@property
97+
def url(self):
98+
""" A DOMString representing the URL of the source. """
99+
return self._url
100+
101+
@property
102+
def withCredentials(self):
103+
""" A boolean value indicating whether the EventSource object was
104+
instantiated with cross-origin (CORS) credentials
105+
set (true), or not (false, the default). """
106+
return self._withCredentials
107+
108+
def close(self):
109+
""" Closes the connection to the EventSource. """
110+
self._readyState = EventSource.CLOSED
111+
# close the thread
112+
self._thread.join()
113+
self._thread = None
114+
115+
def onreadystatechange(self, event):
116+
""" Called when the state of the connection changes. """
117+
pass
118+
119+
def onmessage(self, event):
120+
""" Called when a message is received. """
121+
if self._onmessage is not None:
122+
self._onmessage(event)
123+
124+
def onerror(self, event):
125+
""" Called when an error occurs. """
126+
pass
127+
128+
def onopen(self, event):
129+
""" Called when the connection is established. """
130+
pass
131+
132+
# '''
133+
# NOTE - if we write custom one rather than use lib...
134+
# def _poll(self):
135+
136+
# if self._readyState == EventSource.CLOSED:
137+
# return
138+
139+
# url = 'http://domain.com/events'
140+
# headers = {
141+
# 'Accept': 'text/event-stream',
142+
# 'Cache-Control': 'no-cache',
143+
# 'X-requested-with': 'XMLHttpRequest'
144+
# }
145+
# if self._lastEventId != None:
146+
# headers['Last-Event-ID'] = self._lastEventId
147+
148+
# import requests
149+
# response = requests.get(url, stream=True, headers=headers)
150+
# # TODO - parse repsonse
151+
# '''

0 commit comments

Comments
 (0)