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

View file

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

View file

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

View file

@ -722,18 +722,25 @@ def _async_fetch_image(hass, url):
return cache_images[url]
content, content_type = (None, None)
try:
websession = async_get_clientsession(hass)
response = None
try:
with async_timeout.timeout(10, loop=hass.loop):
response = yield from websession.get(url)
if response.status == 200:
content = yield from response.read()
content_type = response.headers.get(CONTENT_TYPE_HEADER)
yield from response.release()
except asyncio.TimeoutError:
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_urls.append(url)

View file

@ -155,6 +155,7 @@ class YrData(object):
nxt)
if self._nextrun is None or dt_util.utcnow() >= self._nextrun:
resp = None
try:
websession = async_get_clientsession(self.hass)
with async_timeout.timeout(10, loop=self.hass.loop):
@ -163,12 +164,16 @@ class YrData(object):
try_again('{} returned {}'.format(self._url, resp.status))
return
text = yield from resp.text()
self.hass.async_add_job(resp.release())
except (asyncio.TimeoutError, aiohttp.errors.ClientError,
aiohttp.errors.ClientDisconnectedError) as err:
try_again(err)
return
finally:
if resp is not None:
self.hass.async_add_job(resp.release())
try:
import xmltodict
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)
websession = async_get_clientsession(hass)
response = None
try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop):
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:
_LOGGER.error("Failed authentication API call: %s", error)
return False
finally:
if response is not None:
yield from response.close()
try:
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")
return False
response = None
try:
with async_timeout.timeout(TIMEOUT, loop=hass.loop):
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:
_LOGGER.error("Failed getting devices: %s", error)
return False
finally:
if response is not None:
yield from response.close()
yield from async_add_devices(
HookSmartHome(
@ -102,6 +110,7 @@ class HookSmartHome(SwitchDevice):
@asyncio.coroutine
def _send(self, url):
"""Send the url to the Hook API."""
response = None
try:
_LOGGER.debug("Sending: %s", url)
websession = async_get_clientsession(self.hass)
@ -109,11 +118,17 @@ class HookSmartHome(SwitchDevice):
response = yield from websession.get(
url, params={"token": self._token})
data = yield from response.json()
except (asyncio.TimeoutError,
aiohttp.errors.ClientError,
aiohttp.errors.ClientDisconnectedError) as error:
_LOGGER.error("Failed setting state: %s", error)
return False
finally:
if response is not None:
yield from response.close()
_LOGGER.debug("Got: %s", data)
return data['return_value'] == '1'