From 1096232e17b1ac31e76689e7101a9121a52634eb Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Sat, 14 May 2016 15:07:20 -0700 Subject: [PATCH] More WIP --- homeassistant/components/api.py | 71 +++++++++++++++---- homeassistant/components/frontend/__init__.py | 16 +++-- homeassistant/components/http.py | 7 +- tests/components/test_api.py | 33 +++++---- 4 files changed, 88 insertions(+), 39 deletions(-) diff --git a/homeassistant/components/api.py b/homeassistant/components/api.py index 339cd5f29f6..6e1f3c0fe18 100644 --- a/homeassistant/components/api.py +++ b/homeassistant/components/api.py @@ -73,51 +73,70 @@ class APIEventStream(HomeAssistantView): def get(self, request): """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() hass = self.hass + connection_closed = Event() restrict = request.args.get('restrict') if restrict: restrict = restrict.split(',') + restrict = False + def ping(now): """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): """Forward events to the open request.""" + print(id(stop_obj), 'forwarding', event) if event.event_type == EVENT_TIME_CHANGED: pass elif event.event_type == EVENT_HOMEASSISTANT_STOP: - queue.put(stop_obj) + to_write.put(stop_obj) else: - queue.put(json.dumps(event, cls=rem.JSONEncoder)) + to_write.put(json.dumps(event, cls=rem.JSONEncoder)) def stream(): """Stream events to response.""" if restrict: - for event in restrict: - hass.bus.listen(event, forward_events) + for event_type in restrict: + hass.bus.listen(event_type, forward_events) else: 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: - while True: - payload = queue.get() + print(id(stop_obj), 'attached goodness') + + while not connection_closed.is_set(): + try: + print(id(stop_obj), "Try getting obj") + payload = to_write.get(False) if payload is stop_obj: break msg = "data: {}\n\n".format(payload) - + print(id(stop_obj), msg) yield msg.encode("UTF-8") - except GeneratorExit: - pass + except eventlet_queue.Empty: + 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) @@ -127,7 +146,29 @@ class APIEventStream(HomeAssistantView): else: 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): diff --git a/homeassistant/components/frontend/__init__.py b/homeassistant/components/frontend/__init__.py index b7bca3cfd45..7bbb4798508 100644 --- a/homeassistant/components/frontend/__init__.py +++ b/homeassistant/components/frontend/__init__.py @@ -70,7 +70,8 @@ class IndexView(HomeAssistantView): name = "frontend:index" requires_auth = False extra_urls = ['/logbook', '/history', '/map', '/devService', '/devState', - '/devEvent', '/devInfo', '/devTemplate', '/states/'] + '/devEvent', '/devInfo', '/devTemplate', + '/states', '/states/'] def __init__(self, hass): """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.""" - 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 - auth = ('no_password_set' if self.hass.config.api.api_password is None - else request.values.get('api_password', '')) + if self.hass.config.api.api_password is None: + auth = 'no_password_set' + else: + request.values.get('api_password', '') template = self.templates.get_template('index.html') diff --git a/homeassistant/components/http.py b/homeassistant/components/http.py index f7d778dd057..90cd6f2236b 100644 --- a/homeassistant/components/http.py +++ b/homeassistant/components/http.py @@ -87,12 +87,11 @@ class HomeAssistantWSGI(object): """Initilalize the WSGI Home Assistant server.""" from werkzeug.exceptions import BadRequest from werkzeug.wrappers import BaseRequest, AcceptMixin - from werkzeug.contrib.wrappers import JSONRequestMixin from werkzeug.routing import Map from werkzeug.utils import cached_property from werkzeug.wrappers import Response - class Request(BaseRequest, AcceptMixin, JSONRequestMixin): + class Request(BaseRequest, AcceptMixin): """Base class for incoming requests.""" @cached_property @@ -100,8 +99,8 @@ class HomeAssistantWSGI(object): """Get the result of json.loads if possible.""" if not self.data: return None - elif 'json' not in self.environ.get('CONTENT_TYPE', ''): - raise BadRequest('Not a JSON request') + # elif 'json' not in self.environ.get('CONTENT_TYPE', ''): + # raise BadRequest('Not a JSON request') try: return json.loads(self.data.decode( self.charset, self.encoding_errors)) diff --git a/tests/components/test_api.py b/tests/components/test_api.py index e42ae7ce323..bea333aa36b 100644 --- a/tests/components/test_api.py +++ b/tests/components/test_api.py @@ -1,6 +1,6 @@ """The tests for the Home Assistant HTTP component.""" # pylint: disable=protected-access,too-many-public-methods -# from contextlib import closing +from contextlib import closing import json import tempfile import unittest @@ -443,6 +443,9 @@ class TestAPI(unittest.TestCase): # self.assertEqual(listen_count + 1, self._listen_count()) + # # eventlet.sleep(1) + # print('firing event') + # hass.bus.fire('test_event') # hass.pool.block_till_done() @@ -476,20 +479,20 @@ class TestAPI(unittest.TestCase): # data = self._stream_next_event(req) # self.assertEqual('test_event3', data['event_type']) - # def _stream_next_event(self, stream): - # """Test the stream for next event.""" - # data = b'' - # last_new_line = False - # for dat in stream.iter_content(1): - # if dat == b'\n' and last_new_line: - # break - # data += dat - # last_new_line = dat == b'\n' + def _stream_next_event(self, stream): + """Test the stream for next event.""" + data = b'' + last_new_line = False + for dat in stream.iter_content(1): + if dat == b'\n' and last_new_line: + break + data += dat + 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): - # """Return number of event listeners.""" - # return sum(hass.bus.listeners.values()) + def _listen_count(self): + """Return number of event listeners.""" + return sum(hass.bus.listeners.values())