From 4ab362531fee9416f7f2931a5ce2ff3d6bc4d8e6 Mon Sep 17 00:00:00 2001 From: Paulus Schoutsen Date: Fri, 14 Feb 2014 11:57:42 -0800 Subject: [PATCH] Downloader downloads file in seperate thread now so it doesn't block bus queue --- homeassistant/components/downloader.py | 85 +++++++++++++++----------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/homeassistant/components/downloader.py b/homeassistant/components/downloader.py index 5042cf251bb4..9dd67bc67fa4 100644 --- a/homeassistant/components/downloader.py +++ b/homeassistant/components/downloader.py @@ -7,6 +7,7 @@ Provides functionality to download files. import os import logging import re +import threading import homeassistant.util as util @@ -15,6 +16,7 @@ DOMAIN = "downloader" SERVICE_DOWNLOAD_FILE = "download_file" +# pylint: disable=too-many-branches def setup(bus, download_path): """ Listens for download events to download files. """ @@ -36,53 +38,68 @@ def setup(bus, download_path): return False - def _download_file(service): - """ Downloads file specified in the url. """ + def download_file(service): + """ Starts thread to download file specified in the url. """ - try: - req = requests.get(service.data['url'], stream=True) - if req.status_code == 200: - filename = None + if not 'url' in service.data: + logger.error("Service called but 'url' parameter not specified.") + return - if 'content-disposition' in req.headers: - match = re.findall(r"filename=(\S+)", - req.headers['content-disposition']) + def do_download(): + """ Downloads the file. """ + try: + url = service.data['url'] + req = requests.get(url, stream=True) - if len(match) > 0: - filename = match[0].strip("'\" ") + if req.status_code == 200: + filename = None - if not filename: - filename = os.path.basename(service.data['url']).strip() + if 'content-disposition' in req.headers: + match = re.findall(r"filename=(\S+)", + req.headers['content-disposition']) - if not filename: - filename = "ha_download" + if len(match) > 0: + filename = match[0].strip("'\" ") - # Remove stuff to ruin paths - filename = util.sanitize_filename(filename) + if not filename: + filename = os.path.basename( + url).strip() - path, ext = os.path.splitext(os.path.join(download_path, - filename)) + if not filename: + filename = "ha_download" - # If file exist append a number. We test filename, filename_2.. - tries = 1 - final_path = path + ext - while os.path.isfile(final_path): - tries += 1 + # Remove stuff to ruin paths + filename = util.sanitize_filename(filename) - final_path = path + "_{}".format(tries) + ext + path, ext = os.path.splitext(os.path.join(download_path, + filename)) - logger.info("{} -> {}".format( - service.data['url'], final_path)) + # If file exist append a number. + # We test filename, filename_2.. + tries = 1 + final_path = path + ext + while os.path.isfile(final_path): + tries += 1 - with open(final_path, 'wb') as fil: - for chunk in req.iter_content(1024): - fil.write(chunk) + final_path = path + "_{}".format(tries) + ext - except requests.exceptions.ConnectionError: - logger.exception("ConnectionError occured for {}". - format(service.data['url'])) + logger.info("{} -> {}".format( + url, final_path)) + + with open(final_path, 'wb') as fil: + for chunk in req.iter_content(1024): + fil.write(chunk) + + logger.info("Downloading of {} done".format( + url)) + + except requests.exceptions.ConnectionError: + logger.exception("ConnectionError occured for {}". + format(url)) + + threading.Thread(target=do_download).start() bus.register_service(DOMAIN, SERVICE_DOWNLOAD_FILE, - _download_file) + download_file) return True