Files
Artemis/threads.py
2019-05-14 20:17:51 +02:00

202 lines
6.1 KiB
Python

import asyncio
from enum import Enum, auto
from io import BytesIO
from math import ceil
import os.path
from shutil import rmtree
from time import time
from zipfile import ZipFile
import aiohttp
import urllib3
from PyQt5.QtCore import QThread, pyqtSignal
from constants import Constants, Database, ChecksumWhat
from utilities import checksum_ok
class ThreadStatus(Enum):
OK = auto()
NO_CONNECTION_ERR = auto()
UNKNOWN_ERR = auto()
BAD_DOWNLOAD_ERR = auto()
UNDEFINED = auto()
class BaseDownloadThread(QThread):
def __init__(self, parent=None):
super().__init__(parent)
self.status = ThreadStatus.UNDEFINED
def __del__(self):
self.terminate()
self.wait()
class DownloadThread(BaseDownloadThread):
progress = pyqtSignal(int, float)
CHUNK = 1024**2
def __init__(self):
super().__init__()
def __pretty_len(self, byte_obj):
mega = len(byte_obj) / self.CHUNK
if mega.is_integer():
return int(mega)
else:
return ceil(mega)
def __get_download_speed(self, data, delta):
return round(
(len(data) / self.CHUNK) / delta,
2
)
def run(self):
self.status = ThreadStatus.UNDEFINED
raw_data = bytes(0)
try:
db = urllib3.PoolManager().request(
'GET',
Database.LINK_LOC,
preload_content=False
)
while True:
start = time()
data = db.read(self.CHUNK)
delta = time() - start
if not data:
break
raw_data += data
self.progress.emit(
self.__pretty_len(raw_data),
self.__get_download_speed(data, delta)
)
db.release_conn()
except Exception: # No internet connection.
db.release_conn()
self.status = ThreadStatus.NO_CONNECTION_ERR
return
if db.status != 200:
self.status = ThreadStatus.BAD_DOWNLOAD_ERR
return
try:
is_checksum_ok = checksum_ok(raw_data, ChecksumWhat.FOLDER)
except Exception:
self.status = ThreadStatus.NO_CONNECTION_ERR
return
else:
if not is_checksum_ok:
self.status = ThreadStatus.BAD_DOWNLOAD_ERR
return
if os.path.exists(Constants.DATA_FOLDER):
rmtree(Constants.DATA_FOLDER)
try:
self.progress.emit(Constants.EXTRACTING_CODE, 0.0)
with ZipFile(BytesIO(raw_data)) as zipped:
zipped.extractall()
except Exception:
self.status = ThreadStatus.UNKNOWN_ERR
else:
self.status = ThreadStatus.OK
class _AsyncDownloader:
async def _download_resource(self, session, link):
resp = await session.get(link)
return await resp.read()
class UpdateSpaceWeatherThread(BaseDownloadThread, _AsyncDownloader):
__properties = ("xray", "prot_el", "ak_index", "sgas", "geo_storm")
def __init__(self, space_weather_data):
super().__init__()
self.__space_weather_data = space_weather_data
async def __download_property(self, session, property_name):
link = getattr(Constants, "SPACE_WEATHER_" + property_name.upper())
data = await self._download_resource(session, link)
setattr(self.__space_weather_data, property_name, str(data, 'utf-8'))
async def __download_image(self, session, n):
im = await self._download_resource(session, Constants.SPACE_WEATHER_IMGS[n])
self.__space_weather_data.images[n].loadFromData(im)
async def _download_resources(self):
session = aiohttp.ClientSession()
try:
t = []
for p in self.__properties:
t.append(
asyncio.create_task(self.__download_property(session, p))
)
tot_images = range(len(Constants.SPACE_WEATHER_IMGS))
t1 = []
for im_number in tot_images:
t1.append(
asyncio.create_task(self.__download_image(session, im_number))
)
await asyncio.gather(*t, *t1)
except Exception:
self.status = ThreadStatus.UNKNOWN_ERR
else:
self.status = ThreadStatus.OK
finally:
await session.close()
def run(self):
self.status = ThreadStatus.UNDEFINED
asyncio.run(self._download_resources())
class UpdateForecastThread(BaseDownloadThread, _AsyncDownloader):
class _PropertyName(Enum):
FORECAST = auto()
PROBABILITIES = auto()
def __init__(self, parent):
super().__init__()
self.parent = parent
async def __download_property(self, session, link, prop_name):
resp = await self._download_resource(session, link)
resp = str(resp, 'utf-8')
if prop_name is self._PropertyName.FORECAST:
self.parent.forecast = resp
if prop_name is self._PropertyName.PROBABILITIES:
self.parent.probabilities = resp
async def _download_resources(self):
session = aiohttp.ClientSession()
try:
await asyncio.gather(
asyncio.create_task(
self.__download_property(
session,
Constants.SPACE_WEATHER_GEO_STORM,
self._PropertyName.FORECAST
)
),
asyncio.create_task(
self.__download_property(
session,
Constants.FORECAST_PROBABILITIES,
self._PropertyName.PROBABILITIES
)
)
)
except Exception:
self.status = ThreadStatus.UNKNOWN_ERR
else:
self.status = ThreadStatus.OK
finally:
await session.close()
def run(self):
self.status = ThreadStatus.UNDEFINED
asyncio.run(self._download_resources())