More WIP
This commit is contained in:
parent
54ecab7590
commit
1096232e17
4 changed files with 88 additions and 39 deletions
|
@ -73,51 +73,70 @@ class APIEventStream(HomeAssistantView):
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request):
|
||||||
"""Provide a streaming interface for the event bus."""
|
"""Provide a streaming interface for the event bus."""
|
||||||
from eventlet import Queue
|
import eventlet
|
||||||
|
from eventlet import queue as eventlet_queue
|
||||||
|
import queue as thread_queue
|
||||||
|
from threading import Event
|
||||||
|
from time import time
|
||||||
|
|
||||||
queue = Queue()
|
to_write = thread_queue.Queue()
|
||||||
|
# to_write = eventlet.Queue()
|
||||||
stop_obj = object()
|
stop_obj = object()
|
||||||
hass = self.hass
|
hass = self.hass
|
||||||
|
connection_closed = Event()
|
||||||
|
|
||||||
restrict = request.args.get('restrict')
|
restrict = request.args.get('restrict')
|
||||||
if restrict:
|
if restrict:
|
||||||
restrict = restrict.split(',')
|
restrict = restrict.split(',')
|
||||||
|
|
||||||
|
restrict = False
|
||||||
|
|
||||||
def ping(now):
|
def ping(now):
|
||||||
"""Add a ping message to queue."""
|
"""Add a ping message to queue."""
|
||||||
queue.put(STREAM_PING_PAYLOAD)
|
print(id(stop_obj), 'ping')
|
||||||
|
to_write.put(STREAM_PING_PAYLOAD)
|
||||||
|
|
||||||
def forward_events(event):
|
def forward_events(event):
|
||||||
"""Forward events to the open request."""
|
"""Forward events to the open request."""
|
||||||
|
print(id(stop_obj), 'forwarding', event)
|
||||||
if event.event_type == EVENT_TIME_CHANGED:
|
if event.event_type == EVENT_TIME_CHANGED:
|
||||||
pass
|
pass
|
||||||
elif event.event_type == EVENT_HOMEASSISTANT_STOP:
|
elif event.event_type == EVENT_HOMEASSISTANT_STOP:
|
||||||
queue.put(stop_obj)
|
to_write.put(stop_obj)
|
||||||
else:
|
else:
|
||||||
queue.put(json.dumps(event, cls=rem.JSONEncoder))
|
to_write.put(json.dumps(event, cls=rem.JSONEncoder))
|
||||||
|
|
||||||
def stream():
|
def stream():
|
||||||
"""Stream events to response."""
|
"""Stream events to response."""
|
||||||
if restrict:
|
if restrict:
|
||||||
for event in restrict:
|
for event_type in restrict:
|
||||||
hass.bus.listen(event, forward_events)
|
hass.bus.listen(event_type, forward_events)
|
||||||
else:
|
else:
|
||||||
hass.bus.listen(MATCH_ALL, forward_events)
|
hass.bus.listen(MATCH_ALL, forward_events)
|
||||||
|
|
||||||
attached_ping = track_utc_time_change(hass, ping, second=(0, 30))
|
attached_ping = track_utc_time_change(
|
||||||
|
hass, ping, second=(0, 30))
|
||||||
|
|
||||||
try:
|
print(id(stop_obj), 'attached goodness')
|
||||||
while True:
|
|
||||||
payload = queue.get()
|
while not connection_closed.is_set():
|
||||||
|
try:
|
||||||
|
print(id(stop_obj), "Try getting obj")
|
||||||
|
payload = to_write.get(False)
|
||||||
|
|
||||||
if payload is stop_obj:
|
if payload is stop_obj:
|
||||||
break
|
break
|
||||||
|
|
||||||
msg = "data: {}\n\n".format(payload)
|
msg = "data: {}\n\n".format(payload)
|
||||||
|
print(id(stop_obj), msg)
|
||||||
yield msg.encode("UTF-8")
|
yield msg.encode("UTF-8")
|
||||||
except GeneratorExit:
|
except eventlet_queue.Empty:
|
||||||
pass
|
print(id(stop_obj), "queue empty, sleep 0.5")
|
||||||
|
eventlet.sleep(.5)
|
||||||
|
except GeneratorExit:
|
||||||
|
pass
|
||||||
|
|
||||||
|
print(id(stop_obj), "cleaning up")
|
||||||
|
|
||||||
hass.bus.remove_listener(EVENT_TIME_CHANGED, attached_ping)
|
hass.bus.remove_listener(EVENT_TIME_CHANGED, attached_ping)
|
||||||
|
|
||||||
|
@ -127,7 +146,29 @@ class APIEventStream(HomeAssistantView):
|
||||||
else:
|
else:
|
||||||
hass.bus.remove_listener(MATCH_ALL, forward_events)
|
hass.bus.remove_listener(MATCH_ALL, forward_events)
|
||||||
|
|
||||||
return self.Response(stream(), mimetype='text/event-stream')
|
resp = self.Response(stream(), mimetype='text/event-stream')
|
||||||
|
|
||||||
|
def closing():
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print(id(stop_obj), "CLOSING RESPONSE")
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
print()
|
||||||
|
connection_closed.set()
|
||||||
|
|
||||||
|
resp.call_on_close(closing)
|
||||||
|
return resp
|
||||||
|
|
||||||
|
|
||||||
class APIConfigView(HomeAssistantView):
|
class APIConfigView(HomeAssistantView):
|
||||||
|
|
|
@ -70,7 +70,8 @@ class IndexView(HomeAssistantView):
|
||||||
name = "frontend:index"
|
name = "frontend:index"
|
||||||
requires_auth = False
|
requires_auth = False
|
||||||
extra_urls = ['/logbook', '/history', '/map', '/devService', '/devState',
|
extra_urls = ['/logbook', '/history', '/map', '/devService', '/devState',
|
||||||
'/devEvent', '/devInfo', '/devTemplate', '/states/<entity>']
|
'/devEvent', '/devInfo', '/devTemplate',
|
||||||
|
'/states', '/states/<entity_id>']
|
||||||
|
|
||||||
def __init__(self, hass):
|
def __init__(self, hass):
|
||||||
"""Initialize the frontend view."""
|
"""Initialize the frontend view."""
|
||||||
|
@ -84,13 +85,18 @@ class IndexView(HomeAssistantView):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get(self, request):
|
def get(self, request, entity_id=None):
|
||||||
"""Serve the index view."""
|
"""Serve the index view."""
|
||||||
app_url = "frontend-{}.html".format(version.VERSION)
|
if self.hass.wsgi.development:
|
||||||
|
app_url = 'home-assistant-polymer/src/home-assistant.html'
|
||||||
|
else:
|
||||||
|
app_url = "frontend-{}.html".format(version.VERSION)
|
||||||
|
|
||||||
# auto login if no password was set, else check api_password param
|
# auto login if no password was set, else check api_password param
|
||||||
auth = ('no_password_set' if self.hass.config.api.api_password is None
|
if self.hass.config.api.api_password is None:
|
||||||
else request.values.get('api_password', ''))
|
auth = 'no_password_set'
|
||||||
|
else:
|
||||||
|
request.values.get('api_password', '')
|
||||||
|
|
||||||
template = self.templates.get_template('index.html')
|
template = self.templates.get_template('index.html')
|
||||||
|
|
||||||
|
|
|
@ -87,12 +87,11 @@ class HomeAssistantWSGI(object):
|
||||||
"""Initilalize the WSGI Home Assistant server."""
|
"""Initilalize the WSGI Home Assistant server."""
|
||||||
from werkzeug.exceptions import BadRequest
|
from werkzeug.exceptions import BadRequest
|
||||||
from werkzeug.wrappers import BaseRequest, AcceptMixin
|
from werkzeug.wrappers import BaseRequest, AcceptMixin
|
||||||
from werkzeug.contrib.wrappers import JSONRequestMixin
|
|
||||||
from werkzeug.routing import Map
|
from werkzeug.routing import Map
|
||||||
from werkzeug.utils import cached_property
|
from werkzeug.utils import cached_property
|
||||||
from werkzeug.wrappers import Response
|
from werkzeug.wrappers import Response
|
||||||
|
|
||||||
class Request(BaseRequest, AcceptMixin, JSONRequestMixin):
|
class Request(BaseRequest, AcceptMixin):
|
||||||
"""Base class for incoming requests."""
|
"""Base class for incoming requests."""
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
|
@ -100,8 +99,8 @@ class HomeAssistantWSGI(object):
|
||||||
"""Get the result of json.loads if possible."""
|
"""Get the result of json.loads if possible."""
|
||||||
if not self.data:
|
if not self.data:
|
||||||
return None
|
return None
|
||||||
elif 'json' not in self.environ.get('CONTENT_TYPE', ''):
|
# elif 'json' not in self.environ.get('CONTENT_TYPE', ''):
|
||||||
raise BadRequest('Not a JSON request')
|
# raise BadRequest('Not a JSON request')
|
||||||
try:
|
try:
|
||||||
return json.loads(self.data.decode(
|
return json.loads(self.data.decode(
|
||||||
self.charset, self.encoding_errors))
|
self.charset, self.encoding_errors))
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
"""The tests for the Home Assistant HTTP component."""
|
"""The tests for the Home Assistant HTTP component."""
|
||||||
# pylint: disable=protected-access,too-many-public-methods
|
# pylint: disable=protected-access,too-many-public-methods
|
||||||
# from contextlib import closing
|
from contextlib import closing
|
||||||
import json
|
import json
|
||||||
import tempfile
|
import tempfile
|
||||||
import unittest
|
import unittest
|
||||||
|
@ -443,6 +443,9 @@ class TestAPI(unittest.TestCase):
|
||||||
|
|
||||||
# self.assertEqual(listen_count + 1, self._listen_count())
|
# self.assertEqual(listen_count + 1, self._listen_count())
|
||||||
|
|
||||||
|
# # eventlet.sleep(1)
|
||||||
|
# print('firing event')
|
||||||
|
|
||||||
# hass.bus.fire('test_event')
|
# hass.bus.fire('test_event')
|
||||||
# hass.pool.block_till_done()
|
# hass.pool.block_till_done()
|
||||||
|
|
||||||
|
@ -476,20 +479,20 @@ class TestAPI(unittest.TestCase):
|
||||||
# data = self._stream_next_event(req)
|
# data = self._stream_next_event(req)
|
||||||
# self.assertEqual('test_event3', data['event_type'])
|
# self.assertEqual('test_event3', data['event_type'])
|
||||||
|
|
||||||
# def _stream_next_event(self, stream):
|
def _stream_next_event(self, stream):
|
||||||
# """Test the stream for next event."""
|
"""Test the stream for next event."""
|
||||||
# data = b''
|
data = b''
|
||||||
# last_new_line = False
|
last_new_line = False
|
||||||
# for dat in stream.iter_content(1):
|
for dat in stream.iter_content(1):
|
||||||
# if dat == b'\n' and last_new_line:
|
if dat == b'\n' and last_new_line:
|
||||||
# break
|
break
|
||||||
# data += dat
|
data += dat
|
||||||
# last_new_line = dat == b'\n'
|
last_new_line = dat == b'\n'
|
||||||
|
|
||||||
# conv = data.decode('utf-8').strip()[6:]
|
conv = data.decode('utf-8').strip()[6:]
|
||||||
|
|
||||||
# return conv if conv == 'ping' else json.loads(conv)
|
return conv if conv == 'ping' else json.loads(conv)
|
||||||
|
|
||||||
# def _listen_count(self):
|
def _listen_count(self):
|
||||||
# """Return number of event listeners."""
|
"""Return number of event listeners."""
|
||||||
# return sum(hass.bus.listeners.values())
|
return sum(hass.bus.listeners.values())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue