Close aiohttp responses (#4624)

* Close aiohttp responses

* Update generic.py
This commit is contained in:
Paulus Schoutsen 2016-11-30 13:05:58 -08:00 committed by GitHub
parent b1ef5042f9
commit e5504b39ec
6 changed files with 98 additions and 56 deletions

View File

@ -97,8 +97,7 @@ class GenericCamera(Camera):
def fetch(): def fetch():
"""Read image from a URL.""" """Read image from a URL."""
try: try:
kwargs = {'timeout': 10, 'auth': self._auth} response = requests.get(url, timeout=10, auth=self._auth)
response = requests.get(url, **kwargs)
return response.content return response.content
except requests.exceptions.RequestException as error: except requests.exceptions.RequestException as error:
_LOGGER.error('Error getting camera image: %s', error) _LOGGER.error('Error getting camera image: %s', error)
@ -108,13 +107,13 @@ class GenericCamera(Camera):
None, fetch) None, fetch)
# async # async
else: else:
response = None
try: try:
websession = async_get_clientsession(self.hass) websession = async_get_clientsession(self.hass)
with async_timeout.timeout(10, loop=self.hass.loop): with async_timeout.timeout(10, loop=self.hass.loop):
response = yield from websession.get( response = yield from websession.get(
url, auth=self._auth) url, auth=self._auth)
self._last_image = yield from response.read() self._last_image = yield from response.read()
yield from response.release()
except asyncio.TimeoutError: except asyncio.TimeoutError:
_LOGGER.error('Timeout getting camera image') _LOGGER.error('Timeout getting camera image')
return self._last_image return self._last_image
@ -122,6 +121,9 @@ class GenericCamera(Camera):
aiohttp.errors.ClientDisconnectedError) as err: aiohttp.errors.ClientDisconnectedError) as err:
_LOGGER.error('Error getting new camera image: %s', err) _LOGGER.error('Error getting new camera image: %s', err)
return self._last_image return self._last_image
finally:
if response is not None:
self.hass.async_add_job(response.release())
self._last_url = url self._last_url = url
return self._last_image return self._last_image

View File

@ -103,28 +103,31 @@ class MjpegCamera(Camera):
# connect to stream # connect to stream
websession = async_get_clientsession(self.hass) websession = async_get_clientsession(self.hass)
stream = None
response = None
try: try:
with async_timeout.timeout(10, loop=self.hass.loop): with async_timeout.timeout(10, loop=self.hass.loop):
stream = yield from websession.get( stream = yield from websession.get(self._mjpeg_url,
self._mjpeg_url, auth=self._auth)
auth=self._auth
)
except asyncio.TimeoutError:
raise HTTPGatewayTimeout()
response = web.StreamResponse() response = web.StreamResponse()
response.content_type = stream.headers.get(CONTENT_TYPE_HEADER) response.content_type = stream.headers.get(CONTENT_TYPE_HEADER)
yield from response.prepare(request) yield from response.prepare(request)
try:
while True: while True:
data = yield from stream.content.read(102400) data = yield from stream.content.read(102400)
if not data: if not data:
break break
response.write(data) response.write(data)
except asyncio.TimeoutError:
raise HTTPGatewayTimeout()
finally: finally:
if stream is not None:
self.hass.async_add_job(stream.release()) self.hass.async_add_job(stream.release())
if response is not None:
yield from response.write_eof() yield from response.write_eof()
@property @property

View File

@ -73,15 +73,13 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
'version': '1', 'version': '1',
'query': 'SYNO.' 'query': 'SYNO.'
} }
query_req = None
try: try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop): with async_timeout.timeout(TIMEOUT, loop=hass.loop):
query_req = yield from websession_init.get( query_req = yield from websession_init.get(
syno_api_url, syno_api_url,
params=query_payload params=query_payload
) )
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", syno_api_url)
return False
query_resp = yield from query_req.json() query_resp = yield from query_req.json()
auth_path = query_resp['data'][AUTH_API]['path'] auth_path = query_resp['data'][AUTH_API]['path']
@ -89,7 +87,12 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
camera_path = query_resp['data'][CAMERA_API]['path'] camera_path = query_resp['data'][CAMERA_API]['path']
streaming_path = query_resp['data'][STREAMING_API]['path'] streaming_path = query_resp['data'][STREAMING_API]['path']
# cleanup except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", syno_api_url)
return False
finally:
if query_req is not None:
yield from query_req.release() yield from query_req.release()
# Authticate to NAS to get a session id # Authticate to NAS to get a session id
@ -166,21 +169,24 @@ def get_session_id(hass, websession, username, password, login_url):
'session': 'SurveillanceStation', 'session': 'SurveillanceStation',
'format': 'sid' 'format': 'sid'
} }
auth_req = None
try: try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop): with async_timeout.timeout(TIMEOUT, loop=hass.loop):
auth_req = yield from websession.get( auth_req = yield from websession.get(
login_url, login_url,
params=auth_payload params=auth_payload
) )
auth_resp = yield from auth_req.json()
return auth_resp['data']['sid']
except (asyncio.TimeoutError, aiohttp.errors.ClientError): except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", login_url) _LOGGER.exception("Error on %s", login_url)
return False return False
auth_resp = yield from auth_req.json() finally:
if auth_req is not None:
yield from auth_req.release() yield from auth_req.release()
return auth_resp['data']['sid']
class SynologyCamera(Camera): class SynologyCamera(Camera):
"""An implementation of a Synology NAS based IP camera.""" """An implementation of a Synology NAS based IP camera."""
@ -247,29 +253,33 @@ class SynologyCamera(Camera):
'cameraId': self._camera_id, 'cameraId': self._camera_id,
'format': 'mjpeg' 'format': 'mjpeg'
} }
stream = None
response = None
try: try:
with async_timeout.timeout(TIMEOUT, loop=self.hass.loop): with async_timeout.timeout(TIMEOUT, loop=self.hass.loop):
stream = yield from self._websession.get( stream = yield from self._websession.get(
streaming_url, streaming_url,
params=streaming_payload params=streaming_payload
) )
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", streaming_url)
raise HTTPGatewayTimeout()
response = web.StreamResponse() response = web.StreamResponse()
response.content_type = stream.headers.get(CONTENT_TYPE_HEADER) response.content_type = stream.headers.get(CONTENT_TYPE_HEADER)
yield from response.prepare(request) yield from response.prepare(request)
try:
while True: while True:
data = yield from stream.content.read(102400) data = yield from stream.content.read(102400)
if not data: if not data:
break break
response.write(data) response.write(data)
except (asyncio.TimeoutError, aiohttp.errors.ClientError):
_LOGGER.exception("Error on %s", streaming_url)
raise HTTPGatewayTimeout()
finally: finally:
if stream is not None:
self.hass.async_add_job(stream.release()) self.hass.async_add_job(stream.release())
if response is not None:
yield from response.write_eof() yield from response.write_eof()
@property @property

View File

@ -722,18 +722,25 @@ def _async_fetch_image(hass, url):
return cache_images[url] return cache_images[url]
content, content_type = (None, None) content, content_type = (None, None)
try:
websession = async_get_clientsession(hass) websession = async_get_clientsession(hass)
response = None
try:
with async_timeout.timeout(10, loop=hass.loop): with async_timeout.timeout(10, loop=hass.loop):
response = yield from websession.get(url) response = yield from websession.get(url)
if response.status == 200: if response.status == 200:
content = yield from response.read() content = yield from response.read()
content_type = response.headers.get(CONTENT_TYPE_HEADER) content_type = response.headers.get(CONTENT_TYPE_HEADER)
yield from response.release()
except asyncio.TimeoutError: except asyncio.TimeoutError:
pass pass
if content: finally:
if response is not None:
yield from response.release()
if not content:
return (None, None)
cache_images[url] = (content, content_type) cache_images[url] = (content, content_type)
cache_urls.append(url) cache_urls.append(url)

View File

@ -155,6 +155,7 @@ class YrData(object):
nxt) nxt)
if self._nextrun is None or dt_util.utcnow() >= self._nextrun: if self._nextrun is None or dt_util.utcnow() >= self._nextrun:
resp = None
try: try:
websession = async_get_clientsession(self.hass) websession = async_get_clientsession(self.hass)
with async_timeout.timeout(10, loop=self.hass.loop): with async_timeout.timeout(10, loop=self.hass.loop):
@ -163,12 +164,16 @@ class YrData(object):
try_again('{} returned {}'.format(self._url, resp.status)) try_again('{} returned {}'.format(self._url, resp.status))
return return
text = yield from resp.text() text = yield from resp.text()
self.hass.async_add_job(resp.release())
except (asyncio.TimeoutError, aiohttp.errors.ClientError, except (asyncio.TimeoutError, aiohttp.errors.ClientError,
aiohttp.errors.ClientDisconnectedError) as err: aiohttp.errors.ClientDisconnectedError) as err:
try_again(err) try_again(err)
return return
finally:
if resp is not None:
self.hass.async_add_job(resp.release())
try: try:
import xmltodict import xmltodict
self.data = xmltodict.parse(text)['weatherdata'] self.data = xmltodict.parse(text)['weatherdata']

View File

@ -34,6 +34,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
password = config.get(CONF_PASSWORD) password = config.get(CONF_PASSWORD)
websession = async_get_clientsession(hass) websession = async_get_clientsession(hass)
response = None
try: try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop): with async_timeout.timeout(TIMEOUT, loop=hass.loop):
response = yield from websession.post( response = yield from websession.post(
@ -47,6 +48,9 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
aiohttp.errors.ClientDisconnectedError) as error: aiohttp.errors.ClientDisconnectedError) as error:
_LOGGER.error("Failed authentication API call: %s", error) _LOGGER.error("Failed authentication API call: %s", error)
return False return False
finally:
if response is not None:
yield from response.close()
try: try:
token = data['data']['token'] token = data['data']['token']
@ -54,6 +58,7 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
_LOGGER.error("No token. Check username and password") _LOGGER.error("No token. Check username and password")
return False return False
response = None
try: try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop): with async_timeout.timeout(TIMEOUT, loop=hass.loop):
response = yield from websession.get( response = yield from websession.get(
@ -65,6 +70,9 @@ def async_setup_platform(hass, config, async_add_devices, discovery_info=None):
aiohttp.errors.ClientDisconnectedError) as error: aiohttp.errors.ClientDisconnectedError) as error:
_LOGGER.error("Failed getting devices: %s", error) _LOGGER.error("Failed getting devices: %s", error)
return False return False
finally:
if response is not None:
yield from response.close()
yield from async_add_devices( yield from async_add_devices(
HookSmartHome( HookSmartHome(
@ -102,6 +110,7 @@ class HookSmartHome(SwitchDevice):
@asyncio.coroutine @asyncio.coroutine
def _send(self, url): def _send(self, url):
"""Send the url to the Hook API.""" """Send the url to the Hook API."""
response = None
try: try:
_LOGGER.debug("Sending: %s", url) _LOGGER.debug("Sending: %s", url)
websession = async_get_clientsession(self.hass) websession = async_get_clientsession(self.hass)
@ -109,11 +118,17 @@ class HookSmartHome(SwitchDevice):
response = yield from websession.get( response = yield from websession.get(
url, params={"token": self._token}) url, params={"token": self._token})
data = yield from response.json() data = yield from response.json()
except (asyncio.TimeoutError, except (asyncio.TimeoutError,
aiohttp.errors.ClientError, aiohttp.errors.ClientError,
aiohttp.errors.ClientDisconnectedError) as error: aiohttp.errors.ClientDisconnectedError) as error:
_LOGGER.error("Failed setting state: %s", error) _LOGGER.error("Failed setting state: %s", error)
return False return False
finally:
if response is not None:
yield from response.close()
_LOGGER.debug("Got: %s", data) _LOGGER.debug("Got: %s", data)
return data['return_value'] == '1' return data['return_value'] == '1'