table autorefreshing, total score/rank/tie calculations, connectionerror handling, docs

This commit is contained in:
Xevion
2020-06-20 11:55:32 -05:00
parent 0d87130b7b
commit 6a95455a71

66
cli.py
View File

@@ -5,6 +5,7 @@ A simple CLI implementation using the application's API.
""" """
import curses import curses
import time
from datetime import datetime from datetime import datetime
from typing import List from typing import List
@@ -17,59 +18,100 @@ lastAttempt: float = -1
lastUpdate: datetime = None lastUpdate: datetime = None
def refreshScores() -> None: def refreshScores() -> bool:
"""
Refreshes scoreboard data safely, handling a unresponsive or downed scoreboard.
Uses If-Modified-Since headers properly.
Modifies lastAttempt, lastUpdate and scores global vars to track and store data.
:return: True if Score data has been updated.
"""
global lastUpdate, lastAttempt, scores global lastUpdate, lastAttempt, scores
# Send with If-Modified-Since header if this is not the first time # Send with If-Modified-Since header if this is not the first time
headers = {'If-Modified-Since': lastUpdate.strftime('%a, %d %b %Y %I:%M:%S %Z')} if lastUpdate else {} headers = {'If-Modified-Since': lastUpdate.strftime('%a, %d %b %Y %I:%M:%S %Z')} if lastUpdate else {}
# Send request with headers # Send request with headers
resp = requests.get('http://localhost:5000/api/scores/', headers=headers) try:
resp = requests.get('http://127.0.0.1:5000/api/scores/', headers=headers)
except requests.exceptions.ConnectionError:
resp = None
finally:
lastAttempt = time.time()
if resp.ok: if resp is not None and resp.ok:
if resp.status_code == 304 and len(scores) != 0: if resp.status_code == 304 and len(scores) != 0:
pass pass
else: else:
# Changes found, update! # Changes found, update!
lastUpdate = datetime.now(pytz.utc) lastUpdate = datetime.now(pytz.utc)
print(f'"{resp.text}"')
scores = resp.json() scores = resp.json()
# Calculate totals, preliminary sort by total
for team in scores:
team['total'] = sum(team['scores'])
scores.sort(key=lambda team: team['total'], reverse=True)
# Calculate ranks with tie handling logic
for i, team in enumerate(scores):
if i > 0 and scores[i - 1]['total'] == team['total']:
team['rank'] = scores[i - 1]['rank']
else:
team['rank'] = i + 1
return True
return False
def main(screen) -> None:
"""
Mainloop function
:param screen: Curses screen
"""
def main(screen):
while True: while True:
# Refresh scores every 10 seconds
if time.time() - lastAttempt > 10:
refreshScores()
# Get current terminal size and clear # Get current terminal size and clear
y, x = screen.getmaxyx() y, x = screen.getmaxyx()
screen.clear() screen.clear()
# Build table data
global scores global scores
# Print Table to screen table = [[team['rank'], team['id'], team['name'], team['total'], *team['scores']] for team in scores[:y - 4]]
table = [[-1, team['id'], team['name'], team['total'], *team['scores']] for team in scores[:y - 4]] scoreSet = map(str, range(1, len(scores[0]['scores']) + 1)) if scores else []
table.insert(0, ['Rank', 'ID', 'Team Name', 'Total']) table.insert(0, ['Rank', 'ID', 'Team Name', 'T', *scoreSet])
table = SingleTable(table) table = SingleTable(table)
# Show Table
for i, stringRow in enumerate(table.table.split('\n')[:y]): for i, stringRow in enumerate(table.table.split('\n')[:y]):
screen.addstr(i, 0, stringRow[:x]) screen.addstr(i, 0, stringRow[:x])
# Terminal Size
screen.addstr(y - 1, 1, str((x, y))) screen.addstr(y - 1, 1, str((x, y)))
# Update curses screen
screen.refresh()
# Check for quit key # Check for quit key
key = screen.getch() key = screen.getch()
if key == ord('q'): if key == ord('q'):
break break
screen.refresh()
if __name__ == "__main__": if __name__ == "__main__":
stdscr = curses.initscr() stdscr = curses.initscr()
# Setup curses friendly terminal flags, run app # Setup curses friendly terminal flags, run app
try: try:
refreshScores()
curses.cbreak() curses.cbreak()
stdscr.nodelay(1) stdscr.nodelay(1)
curses.noecho() curses.noecho()
curses.curs_set(False) curses.curs_set(False)
stdscr.keypad(True) stdscr.keypad(True)
refreshScores()
main(stdscr) main(stdscr)
# Undo curses terminal options # Undo curses terminal options
finally: finally: