mirror of
https://github.com/FAUSheppy/open-web-leaderboard.git
synced 2025-12-06 07:01:36 +01:00
adapt to refactor 2020 of skillbird
This commit is contained in:
53
database.py
Normal file
53
database.py
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
import json
|
||||||
|
import sqlite3
|
||||||
|
import player
|
||||||
|
|
||||||
|
DB_BASE = "file:{}?mode=ro"
|
||||||
|
|
||||||
|
def getTotalPlayers(database):
|
||||||
|
'''Get the total number of players in the database'''
|
||||||
|
|
||||||
|
print(DB_BASE.format(database))
|
||||||
|
conn = sqlite3.connect(DB_BASE.format(database), uri=True)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
cursor.execute("SELECT Count(*) FROM players")
|
||||||
|
count = cursor.fetchone()[0]
|
||||||
|
conn.close()
|
||||||
|
return count
|
||||||
|
|
||||||
|
|
||||||
|
def getRankRange(database, start, end):
|
||||||
|
'''Get a range of players by rank'''
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DB_BASE.format(database), uri=True)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
limit = end - start
|
||||||
|
cursor.execute("Select * FROM players ORDER BY (mu - 2*sigma) DESC LIMIT ? OFFSET ?", (limit, start))
|
||||||
|
rows = cursor.fetchall()
|
||||||
|
conn.close()
|
||||||
|
playerList = []
|
||||||
|
for row in rows:
|
||||||
|
playerList += [player.PlayerInLeaderboard(row)]
|
||||||
|
|
||||||
|
return playerList
|
||||||
|
|
||||||
|
def findPlayerByName(playerName):
|
||||||
|
'''Find a player by his name (prefer fullmatch)'''
|
||||||
|
|
||||||
|
conn = sqlite3.connect(DB_BASE.format(database), uri=True)
|
||||||
|
cursor = conn.cursor()
|
||||||
|
playerNamePrepared = "%{}%".format(playerName.replace("%", "%%"))
|
||||||
|
cursor.execute("SELECT * FROM players WHERE name == ?", (playerName,))
|
||||||
|
row = cursor.fetone()
|
||||||
|
|
||||||
|
playerRow = None
|
||||||
|
if row:
|
||||||
|
cursor.execute("SELECT * FROM players WHERE name LIKE ?", (playerNamePrepared,))
|
||||||
|
row = cursor.fetchone()[0]
|
||||||
|
if not row:
|
||||||
|
conn.close()
|
||||||
|
return None
|
||||||
|
|
||||||
|
conn.close()
|
||||||
|
return players.Leaderboard(playerRow)
|
||||||
36
player.py
Normal file
36
player.py
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
#!/usr/bin/python3
|
||||||
|
import flask
|
||||||
|
|
||||||
|
class PlayerInLeaderboard:
|
||||||
|
def __init__(self, dbRow):
|
||||||
|
'''Initialize a player object later to be serialized to HTML'''
|
||||||
|
|
||||||
|
playerID, name, lastGame, wins, mu, sigma, games = dbRow
|
||||||
|
|
||||||
|
# set relevant values #
|
||||||
|
self.name = name
|
||||||
|
self.playerID = playerID
|
||||||
|
self.mu = mu
|
||||||
|
self.sigma = sigma
|
||||||
|
self.rating = int(self.mu) - int(self.sigma)
|
||||||
|
self.games = int(games)
|
||||||
|
self.wins = int(wins)
|
||||||
|
self.loses = self.games - self.wins
|
||||||
|
|
||||||
|
# determine winratio #
|
||||||
|
if self.games == 0:
|
||||||
|
self.winratio = "N/A"
|
||||||
|
else:
|
||||||
|
self.winratio = str(int(self.wins/self.games * 100))
|
||||||
|
|
||||||
|
def getLineHTML(self, rank):
|
||||||
|
'''Build a single line for a specific player in the leaderboard'''
|
||||||
|
|
||||||
|
string = flask.render_template("playerLine.html", \
|
||||||
|
playerRank = rank, \
|
||||||
|
playerName = self.name, \
|
||||||
|
playerRating = self.rating, \
|
||||||
|
playerGames = self.games, \
|
||||||
|
playerWinratio = self.winratio)
|
||||||
|
|
||||||
|
return flask.Markup(string)
|
||||||
77
server.py
77
server.py
@@ -4,33 +4,20 @@ import requests
|
|||||||
import argparse
|
import argparse
|
||||||
import flask_caching as fcache
|
import flask_caching as fcache
|
||||||
import json
|
import json
|
||||||
|
import database as db
|
||||||
|
|
||||||
|
|
||||||
app = flask.Flask("open-leaderboard")
|
app = flask.Flask("open-leaderboard")
|
||||||
cache = fcache.Cache(app, config={'CACHE_TYPE': 'simple'})
|
cache = fcache.Cache(app, config={'CACHE_TYPE': 'simple'})
|
||||||
cache.init_app(app)
|
cache.init_app(app)
|
||||||
|
|
||||||
SERVER = "localhost:5001"
|
SEGMENT=100
|
||||||
LOCATION = "/rankrange"
|
|
||||||
PARAM_START = "start"
|
|
||||||
PARAM_END = "end"
|
|
||||||
|
|
||||||
BASE_URL = "http://{server}{path}?{paramStart}={start}&{paramEnd}={end}"
|
class PlayerInLeaderboard:
|
||||||
MAX_ENTRY = "http://{server}/getmaxentries"
|
def __init__(self, dbRow):
|
||||||
FIND_PLAYER = "http://{server}/getplayer?name={pname}"
|
|
||||||
SEGMENT = 100
|
|
||||||
SEPERATOR = ','
|
|
||||||
|
|
||||||
class Player:
|
|
||||||
def __init__(self, line):
|
|
||||||
'''Initialize a player object later to be serialized to HTML'''
|
'''Initialize a player object later to be serialized to HTML'''
|
||||||
|
|
||||||
# parse input line #
|
name, playerID, rating, games, wins = dbRow
|
||||||
try:
|
|
||||||
name, playerID, rating, games, wins = line.split(SEPERATOR)
|
|
||||||
except ValueError as e:
|
|
||||||
print("Failed to parse line: {}".format(line))
|
|
||||||
raise e
|
|
||||||
|
|
||||||
# set relevant values #
|
# set relevant values #
|
||||||
self.name = name
|
self.name = name
|
||||||
@@ -58,21 +45,6 @@ class Player:
|
|||||||
|
|
||||||
# mark returned string as preformated html #
|
# mark returned string as preformated html #
|
||||||
return flask.Markup(string)
|
return flask.Markup(string)
|
||||||
|
|
||||||
def requestRange(start, end):
|
|
||||||
'''Request a range from the rating server'''
|
|
||||||
|
|
||||||
start = max(start, 0)
|
|
||||||
|
|
||||||
# request information from rating server #
|
|
||||||
requestURL = BASE_URL.format(server=SERVER, \
|
|
||||||
path=LOCATION, \
|
|
||||||
paramStart=PARAM_START, \
|
|
||||||
paramEnd=PARAM_END, \
|
|
||||||
start=start, \
|
|
||||||
end=end)
|
|
||||||
|
|
||||||
return str(requests.get(requestURL).content, "utf-8")
|
|
||||||
|
|
||||||
@app.route('/leaderboard')
|
@app.route('/leaderboard')
|
||||||
@app.route('/')
|
@app.route('/')
|
||||||
@@ -109,24 +81,15 @@ def leaderboard():
|
|||||||
end = start + SEGMENT
|
end = start + SEGMENT
|
||||||
|
|
||||||
|
|
||||||
# request and check if we are within range #
|
# compute range #
|
||||||
maxEntryUrl = MAX_ENTRY.format(server=SERVER)
|
maxEntry = db.getTotalPlayers(app.config["DB_PATH"])
|
||||||
maxEntry = int(requests.get(maxEntryUrl).content)
|
|
||||||
reachedEnd = False
|
reachedEnd = False
|
||||||
if end > maxEntry:
|
if end > maxEntry:
|
||||||
start = maxEntry - ( maxEntry % SEGMENT ) - 1
|
start = maxEntry - ( maxEntry % SEGMENT ) - 1
|
||||||
end = maxEntry - 1
|
end = maxEntry - 1
|
||||||
reachedEnd = True
|
reachedEnd = True
|
||||||
|
|
||||||
# do the actual request #
|
playerList = db.getRankRange(app.config["DB_PATH"], start, end)
|
||||||
responseString = requestRange(start, end)
|
|
||||||
|
|
||||||
# create relevant html-lines from player
|
|
||||||
players = [Player(line) for line in responseString.split("\n")]
|
|
||||||
|
|
||||||
# sanity check reponse #
|
|
||||||
if len(players) > 100:
|
|
||||||
raise ValueError("Bad reponse from rating server")
|
|
||||||
|
|
||||||
columContent = flask.Markup(flask.render_template("playerLine.html", \
|
columContent = flask.Markup(flask.render_template("playerLine.html", \
|
||||||
playerRank="Rank", \
|
playerRank="Rank", \
|
||||||
@@ -143,8 +106,9 @@ def leaderboard():
|
|||||||
# fix <100 player start at 0 #
|
# fix <100 player start at 0 #
|
||||||
if maxEntry <= 100:
|
if maxEntry <= 100:
|
||||||
start = max(start, 0)
|
start = max(start, 0)
|
||||||
|
|
||||||
finalResponse = flask.render_template("base.html", playerList=players, \
|
print(playerList)
|
||||||
|
finalResponse = flask.render_template("base.html", playerList=playerList, \
|
||||||
columNames=columContent, \
|
columNames=columContent, \
|
||||||
start=start, \
|
start=start, \
|
||||||
endOfBoardIndicator=endOfBoardIndicator, \
|
endOfBoardIndicator=endOfBoardIndicator, \
|
||||||
@@ -163,23 +127,14 @@ def init():
|
|||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
parser = argparse.ArgumentParser(description='Start open-leaderboard', \
|
parser = argparse.ArgumentParser(description='Start open-leaderboard', \
|
||||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||||
parser.add_argument('--rating-server', default=SERVER, \
|
|
||||||
help='Compatible rating server to query')
|
|
||||||
parser.add_argument('--request-url', default=LOCATION, \
|
|
||||||
help='API location for rating range')
|
|
||||||
parser.add_argument('--param-start', default=PARAM_START, \
|
|
||||||
help='Name of parameter annotating the start of the rating range')
|
|
||||||
parser.add_argument('--param-end', default=PARAM_END, \
|
|
||||||
help='Name of parameter annotating the end of the rating range')
|
|
||||||
parser.add_argument('--interface', default="localhost", \
|
parser.add_argument('--interface', default="localhost", \
|
||||||
help='Interface on which flask (this server) will take requests on')
|
help='Interface on which flask (this server) will take requests on')
|
||||||
parser.add_argument('--port', default="5002", \
|
parser.add_argument('--port', default="5002", \
|
||||||
help='Port on which flask (this server) will take requests on')
|
help='Port on which flask (this server) will take requests on')
|
||||||
|
|
||||||
|
parser.add_argument('--skillbird-db', required=True, help='skillbird database (overrides web connection if set)')
|
||||||
|
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
app.config["DB_PATH"] = args.skillbird_db
|
||||||
SERVER = args.rating_server
|
|
||||||
LOCATION = args.request_url
|
|
||||||
PARAM_START = args.param_start
|
|
||||||
PARAM_END = args.param_end
|
|
||||||
|
|
||||||
app.run(host=args.interface, port=args.port)
|
app.run(host=args.interface, port=args.port)
|
||||||
|
|||||||
Reference in New Issue
Block a user