Replace requests with aiohttp and make warpy asynchronous

This is a major change in how this overlay will be defined as it will now be asynchronous. After doing
a bit of research this is likely to be the best option since there will be various functions polling
the API for information. If one requests takes to long the GUI will get hung up, this resolves that
issue.

Note: This is a first dive into asynchronous so future commits may aim to resolve sloppy asynchronous
implementations.
This commit is contained in:
雲華
2021-05-02 00:36:42 -04:00
parent 5a92803bbe
commit c3a5f10b82
3 changed files with 246 additions and 124 deletions

141
.gitignore vendored Normal file
View File

@@ -0,0 +1,141 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
.idea/

View File

@@ -1,9 +1,10 @@
import asyncio
import aiohttp
import tkinter as tk import tkinter as tk
import warframe_api as warpy import warframe_api as warpy
import win32gui import win32gui
import win32api import win32api
import win32con import win32con
import requests
from ctypes import windll from ctypes import windll
GWL_EXSTYLE = -20 GWL_EXSTYLE = -20
@@ -86,7 +87,9 @@ else:
timers = tk.Frame(master=root, bg="#FFFFFF", width=340, height=160, cursor="none") timers = tk.Frame(master=root, bg="#FFFFFF", width=340, height=160, cursor="none")
warframe = warpy.WarframeAPI("pc", requests.session())
loop = asyncio.get_event_loop()
warframe = warpy.WarframeAPI("pc", loop=loop)
timers.grid(row=0, column=0) timers.grid(row=0, column=0)
@@ -102,10 +105,11 @@ cambion_timer.grid(row=0, column=3)
vallis_timer.grid(row=0, column=5) vallis_timer.grid(row=0, column=5)
def current_cycles(): async def current_cycles():
cetus_status = warframe.cetus_status() print("Running...")
vallis_status = warframe.vallis_status() cetus_status = await warframe.cetus_status()
cambion_status = warframe.cambion_status() vallis_status = await warframe.vallis_status()
cambion_status = await warframe.cambion_status()
if cetus_status["isDay"]: if cetus_status["isDay"]:
cetus_timer.config(text="Day") cetus_timer.config(text="Day")
else: else:
@@ -118,6 +122,6 @@ def current_cycles():
root.after(300000, current_cycles) root.after(300000, current_cycles)
current_cycles() loop.run_until_complete(current_cycles())
root.mainloop() root.mainloop()

View File

@@ -1,160 +1,137 @@
from requests import request import asyncio
import aiohttp
WARFRAME_API = 'https://api.warframestat.us'
class NonPlatformError(Exception): class NonPlatformError(Exception):
pass pass
def catch_status_code(f):
def func(*args, **kwargs):
response = f(*args, **kwargs)
if response.status_code != 200:
response.raise_for_status()
return response.json()
return func
class WarframeAPI: class WarframeAPI:
_platforms = ['pc', 'ps4', 'xb1', 'swi'] _platforms = ['pc', 'ps4', 'xb1', 'swi']
def __init__(self, platform: str, session: request, language: str = 'en'): def __init__(self, platform: str, language: str = 'en', loop=None):
if platform not in self._platforms: if platform not in self._platforms:
raise NonPlatformError(platform) raise NonPlatformError(platform)
self.platform = platform self.platform = platform
self.language = language self.language = language
self.api = 'https://api.warframestat.us/{platform}'.format(platform=self.platform) self._loop = asyncio.get_event_loop() if loop is None else loop
self.session = session self.session = aiohttp.ClientSession(loop=self._loop)
@catch_status_code async def _fetch(self, url):
def worldstate(self): async with self.session.get(url) as response:
response = self.session.get(self.api) resp = await response.json()
return response return resp
@catch_status_code
def alerts(self):
response = self.session.get(self.api + "/alerts")
return response
@catch_status_code async def worldstate(self):
def arbitration(self): url = WARFRAME_API + "/{platform}".format(platform=self.platform)
response = self.session.get(self.api + "/arbitration") return await self._fetch(url)
return response # response = self.session.get(self.api)
# return response
@catch_status_code async def alerts(self):
def cambion_status(self): url = WARFRAME_API + "/{platform}/alerts".format(platform=self.platform)
response = self.session.get(self.api + "/cambionCycle") return await self._fetch(url)
return response
@catch_status_code async def arbitration(self):
def cetus_status(self): url = WARFRAME_API + "/{platform}/arbitration".format(platform=self.platform)
response = self.session.get(self.api + "/cetusCycle") return await self._fetch(url)
return response
@catch_status_code async def cambion_status(self):
def conclave_challenges(self): url = WARFRAME_API + "/{platform}/cambionCycle".format(platform=self.platform)
response = self.session.get(self.api + "/cetusCycle") return await self._fetch(url)
return response
@catch_status_code async def cetus_status(self):
def construction_progress(self): url = WARFRAME_API + "/{platform}/cetusCycle".format(platform=self.platform)
response = self.session.get(self.api + "/constructionProgress") return await self._fetch(url)
return response
@catch_status_code async def conclave_challenges(self, query: str = None):
def darvo_deal(self): url = WARFRAME_API + "/{platform}/conclaveChallenges".format(platform=self.platform)
response = self.session.get(self.api + "/dailyDeals") return await self._fetch(url)
return response
@catch_status_code async def construction_progress(self):
def earth_cycle(self): url = WARFRAME_API + "/{platform}/constructionProgress".format(platform=self.platform)
response = self.session.get(self.api + "/earthCycle") return await self._fetch(url)
return response
@catch_status_code async def darvo_deal(self):
def ongoing_events(self): url = WARFRAME_API + "/{platform}/dailyDeals".format(platform=self.platform)
response = self.session.get(self.api + "/events") return await self._fetch(url)
return response
@catch_status_code async def earth_cycle(self):
def fissures(self): url = WARFRAME_API + "/{platform}/earthCycle".format(platform=self.platform)
response = self.session.get(self.api + "/fissures") return await self._fetch(url)
return response
@catch_status_code async def ongoing_events(self):
def darvo_flash_sale(self): url = WARFRAME_API + "/{platform}/events".format(platform=self.platform)
response = self.session.get(self.api + "/flashSales") return await self._fetch(url)
return response
@catch_status_code async def fissures(self):
def global_upgrades(self): url = WARFRAME_API + "/{platform}/fissures".format(platform=self.platform)
response = self.session.get(self.api + "/globalUpgrades") return await self._fetch(url)
return response
@catch_status_code
def invasions(self): async def darvo_flash_sale(self):
response = self.session.get(self.api + "/invasions") url = WARFRAME_API + "/{platform}/flashSales".format(platform=self.platform)
return response return await self._fetch(url)
@catch_status_code async def global_upgrades(self):
def kuva_nodes(self): url = WARFRAME_API + "/{platform}/globalUpgrades".format(platform=self.platform)
response = self.session.get(self.api + "/kuva") return await self._fetch(url)
return response
@catch_status_code async def invasions(self):
def news(self): url = WARFRAME_API + "/{platform}/invasions".format(platform=self.platform)
response = self.session.get(self.api + "/news") return await self._fetch(url)
return response
@catch_status_code async def kuva_nodes(self):
def nightwave(self): url = WARFRAME_API + "/{platform}/kuva".format(platform=self.platform)
response = self.session.get(self.api + "/nightwave") return await self._fetch(url)
return response
@catch_status_code async def news(self):
def persistent_enemy_data(self): url = WARFRAME_API + "/{platform}/news".format(platform=self.platform)
response = self.session.get(self.api + "/persistentEnemies") return await self._fetch(url)
return response
@catch_status_code async def nightwave(self):
def riven_stats(self, query: str = None): url = WARFRAME_API + "/{platform}/nightwave".format(platform=self.platform)
return await self._fetch(url)
async def persistent_enemy_data(self):
url = WARFRAME_API + "/{platform}/persistentEnemies".format(platform=self.platform)
return await self._fetch(url)
async def riven_stats(self, query: str = None):
if query: if query:
response = self.session.get(self.api + "/rivens/search/{query}".format(query=query)) url = WARFRAME_API + "/{platform}/rivens/search/{query}".format(platform=self.platform, query=query)
else: else:
response = self.session.get(self.api + "/rivens") url = WARFRAME_API + "/{platform}/rivens".format(platform=self.platform)
return response return await self._fetch(url)
@catch_status_code async def sentient_outpost(self):
def sentient_outpost(self): url = WARFRAME_API + "/{platform}/sentientOutposts".format(platform=self.platform)
response = self.session.get(self.api + "/sentientOutposts") return await self._fetch(url)
return response
@catch_status_code async def sanctuary_status(self):
def sanctuary_status(self): url = WARFRAME_API + "/{platform}/simaris".format(platform=self.platform)
response = self.session.get(self.api + "/simaris") return await self._fetch(url)
return response
@catch_status_code async def sortie(self):
def sortie(self): url = WARFRAME_API + "/{platform}/sortie".format(platform=self.platform)
response = self.session.get(self.api + "/sortie") return await self._fetch(url)
return response
@catch_status_code async def syndicate_nodes(self):
def syndicate_nodes(self): url = WARFRAME_API + "/{platform}/syndicateMissions".format(platform=self.platform)
response = self.session.get(self.api + "/syndicateMissions") return await self._fetch(url)
return response
@catch_status_code async def worldstate_timestamp(self):
def worldstate_timestamp(self): url = WARFRAME_API + "/{platform}/timestamp".format(platform=self.platform)
response = self.session.get(self.api + "/timestamp") return await self._fetch(url)
return response
@catch_status_code async def vallis_status(self):
def vallis_status(self): url = WARFRAME_API + "/{platform}/vallisCycle".format(platform=self.platform)
response = self.session.get(self.api + "/vallisCycle") return await self._fetch(url)
return response
@catch_status_code async def void_trader(self):
def void_trader(self): url = WARFRAME_API + "/{platform}/voidTrader".format(platform=self.platform)
response = self.session.get(self.api + "/voidTrader") return await self._fetch(url)
return response