@cache_region('hourly_term')
-def get_summary_stats():
+def get_summary_stats(scope="all"):
"""
- Gets the following aggregate or "summary" statistics about stats:
- - the total number of players (total_players)
- - the total number of servers (total_servers)
- - the total number of games (total_games)
- - the total number of dm games (dm_games)
- - the total number of duel games (duel_games)
- - the total number of ctf games (ctf_games)
-
- It is worth noting that there is also a table built to house these
- stats in case the query in this function becomes too long for the
- one time it runs per hour. In that case there is a script in the
- xonstatdb repo - update_summary_stats.sql - that can be used via
- cron to update the data offline.
- """
- summary_stats = DBSession.query("total_players", "total_servers",
- "total_games", "dm_games", "duel_games", "ctf_games").\
- from_statement(
- """
- with total_games as (
- select game_type_cd, count(*) total_games
- from games
- where game_type_cd in ('duel', 'dm', 'ctf')
- group by game_type_cd
- ),
- total_players as (
- select count(*) total_players
- from players
- where active_ind = true
- ),
- total_servers as (
- select count(*) total_servers
- from servers
- where active_ind = true
- )
- select tp.total_players, ts.total_servers, dm.total_games+
- duel.total_games+ctf.total_games total_games,
- dm.total_games dm_games, duel.total_games duel_games,
- ctf.total_games ctf_games
- from total_games dm, total_games duel, total_games ctf,
- total_players tp, total_servers ts
- where dm.game_type_cd = 'dm'
- and ctf.game_type_cd = 'ctf'
- and duel.game_type_cd = 'duel'
- """
- ).one()
-
- return summary_stats
+ Gets the following aggregate statistics according to the provided scope:
+ - the number of active players
+ - the number of games per game type
-@cache_region('hourly_term')
-def get_day_summary_stats(request):
- """
- Gets the following aggregate statistics about the past 24 hours:
- - the number of active players (day_active_players)
- - the number of games per game type (day_games)
+ Scope can be "all" or "day".
- This information is then summarized into a string which is passed
+ The fetched information is summarized into a string which is passed
directly to the template.
"""
- try:
- # only games played during this range are considered
- right_now = datetime.now()
- cutoff_dt = right_now - timedelta(days=1)
-
- games = DBSession.query(Game.game_type_cd, func.count()).\
- filter(expr.between(Game.create_dt, cutoff_dt, right_now)).\
- group_by(Game.game_type_cd).\
- order_by(expr.desc(func.count())).all()
+ if scope not in ["all", "day"]:
+ scope = "all"
- total_games = 0
- for total in games:
- total_games += total[1]
+ try:
+ ss = DBSession.query("num_players", "game_type_cd", "num_games").\
+ from_statement(
+ "SELECT num_players, game_type_cd, num_games "
+ "FROM summary_stats_mv "
+ "WHERE scope = :scope "
+ "ORDER BY sort_order "
+ ).params(scope=scope).all()
i = 1
+ total_games = 0
other_games = 0
- for total in games:
+ for row in ss:
+ # the number of players is constant in each row
+ total_players = row.num_players
+
+ total_games += row.num_games
+
+ # we can't show all game types on the single summary line, so any
+ # past the fifth one will get bundled in to an "other" count
if i > 5:
- other_games += total[1]
+ other_games += row.num_games
i += 1
- active_players = DBSession.query(func.count(sa.distinct(PlayerGameStat.player_id))).\
- filter(PlayerGameStat.player_id > 2).\
- filter(expr.between(PlayerGameStat.create_dt, cutoff_dt, right_now)).\
- one()[0]
-
# don't send anything if we don't have any activity
if total_games == 0:
- day_stat_line = None
+ stat_line = None
else:
# This is ugly because we're doing template-like stuff within the
# view code. The alternative isn't any better, though: we would
# have to assemble the string inside the template by using a Python
# code block. For now I'll leave it like this since it is the lesser
# of two evils IMO.
- in_paren = ", ".join(["{} {}".format(
- g[1],
- "<a href='{}'>{}</a>".format(
- request.route_url("game_index", _query={'type':g[0]}),
- g[0]
- )
- ) for g in games[:5]])
-
- if len(games) > 5:
- in_paren += ", {} other".format(other_games)
-
- day_stat_line = "{} active players and {} games ({}) in the past 24 hours.".format(
- active_players,
+ # Also we need to hard-code the URL structure in here to allow caching,
+ # which also sucks.
+ in_paren = "; ".join(["{:2,d} {}".format(
+ g.num_games,
+ "<a href='/games?type={0}'>{0}</a>".format(g.game_type_cd)
+ ) for g in ss[:5]])
+
+ if other_games > 0:
+ in_paren += "; {:2,d} other".format(other_games)
+
+ stat_line = "{:2,d} players and {:2,d} games ({})".format(
+ total_players,
total_games,
in_paren
)
except Exception as e:
- day_stat_line = None
+ raise e
+ stat_line = None
+
+ return stat_line
- return day_stat_line
@cache_region('hourly_term')
def get_ranks(game_type_cd):
return ranks
-def top_players_by_time_q(cutoff_days):
- """
- Query for the top players by the amount of time played during a date range.
-
- Games older than cutoff_days days old are ignored.
- """
-
- # only games played during this range are considered
- right_now = datetime.utcnow()
- cutoff_dt = right_now - timedelta(days=cutoff_days)
-
- top_players_q = DBSession.query(Player.player_id, Player.nick,
- func.sum(PlayerGameStat.alivetime)).\
- filter(Player.player_id == PlayerGameStat.player_id).\
- filter(Player.player_id > 2).\
- filter(expr.between(PlayerGameStat.create_dt, cutoff_dt, right_now)).\
- order_by(expr.desc(func.sum(PlayerGameStat.alivetime))).\
- group_by(Player.nick).\
- group_by(Player.player_id)
-
- return top_players_q
-
-
@cache_region('hourly_term')
-def get_top_players_by_time(cutoff_days):
+def get_top_players_by_time(limit=None, start=None):
"""
The top players by the amount of time played during a date range.
-
- Games older than cutoff_days days old are ignored.
"""
- # how many to retrieve
- count = 10
-
- # only games played during this range are considered
- right_now = datetime.utcnow()
- cutoff_dt = right_now - timedelta(days=cutoff_days)
-
- top_players_q = top_players_by_time_q(cutoff_days)
+ q = DBSession.query(ActivePlayer)
- top_players = top_players_q.limit(count).all()
+ if start is not None:
+ q = q.filter(ActivePlayer.sort_order >= start)
- top_players = [(player_id, html_colors(nick), score) \
- for (player_id, nick, score) in top_players]
+ q = q.order_by(ActivePlayer.sort_order)
- return top_players
+ if limit is not None:
+ q = q.limit(limit)
-
-def top_servers_by_players_q(cutoff_days):
- """
- Query to get the top servers by the amount of players active
- during a date range.
-
- Games older than cutoff_days days old are ignored.
- """
- # only games played during this range are considered
- right_now = datetime.utcnow()
- cutoff_dt = right_now - timedelta(days=cutoff_days)
-
- top_servers_q = DBSession.query(Server.server_id, Server.name,
- func.count()).\
- filter(Game.server_id==Server.server_id).\
- filter(expr.between(Game.create_dt, cutoff_dt, right_now)).\
- order_by(expr.desc(func.count(Game.game_id))).\
- group_by(Server.server_id).\
- group_by(Server.name)
-
- return top_servers_q
+ return q.all()
@cache_region('hourly_term')
-def get_top_servers_by_players(cutoff_days):
+def get_top_servers_by_games(limit=None, start=None):
"""
- The top servers by the amount of players active during a date range.
-
- Games older than cutoff_days days old are ignored.
+ The top servers by the number of games played during a date range.
"""
- # how many to retrieve
- count = 10
+ q = DBSession.query(ActiveServer)
- top_servers = top_servers_by_players_q(cutoff_days).limit(count).all()
+ if start is not None:
+ q = q.filter(ActiveServer.sort_order >= start)
- return top_servers
+ q = q.order_by(ActiveServer.sort_order)
+ if limit is not None:
+ q = q.limit(limit)
-def top_maps_by_times_played_q(cutoff_days):
- """
- Query to retrieve the top maps by the amount of times it was played
- during a date range.
-
- Games older than cutoff_days days old are ignored.
- """
- # only games played during this range are considered
- right_now = datetime.utcnow()
- cutoff_dt = right_now - timedelta(days=cutoff_days)
-
- top_maps_q = DBSession.query(Game.map_id, Map.name,
- func.count()).\
- filter(Map.map_id==Game.map_id).\
- filter(expr.between(Game.create_dt, cutoff_dt, right_now)).\
- order_by(expr.desc(func.count())).\
- group_by(Game.map_id).\
- group_by(Map.name)
-
- return top_maps_q
+ return q.all()
@cache_region('hourly_term')
-def get_top_maps_by_times_played(cutoff_days):
+def get_top_maps_by_games(limit=None, start=None):
"""
- The top maps by the amount of times it was played during a date range.
-
- Games older than cutoff_days days old are ignored.
+ The top maps by the number of games played during a date range.
"""
- # how many to retrieve
- count = 10
+ q = DBSession.query(ActiveMap)
+
+ if start is not None:
+ q = q.filter(ActiveMap.sort_order >= start)
+
+ q = q.order_by(ActiveMap.sort_order)
- top_maps = top_maps_by_times_played_q(cutoff_days).limit(count).all()
+ if limit is not None:
+ q = q.limit(limit)
- return top_maps
+ return q.all()
def _main_index_data(request):
recent_games_count = 20
# summary statistics for the tagline
- try:
- summary_stats = get_summary_stats()
- day_stat_line = get_day_summary_stats(request)
+ stat_line = get_summary_stats("all")
+ day_stat_line = get_summary_stats("day")
- except:
- summary_stats = None
- day_stat_line = None
# the three top ranks tables
ranks = []
back_then = datetime.utcnow() - timedelta(days=leaderboard_lifetime)
# top players by playing time
- top_players = get_top_players_by_time(leaderboard_lifetime)
+ top_players = get_top_players_by_time(10)
- # top servers by number of total players played
- top_servers = get_top_servers_by_players(leaderboard_lifetime)
+ # top servers by number of games
+ top_servers = get_top_servers_by_games(10)
# top maps by total times played
- top_maps = get_top_maps_by_times_played(leaderboard_lifetime)
+ top_maps = get_top_maps_by_games(10)
# recent games played in descending order
rgs = recent_games_q(cutoff=back_then).limit(recent_games_count).all()
'top_maps':top_maps,
'recent_games':recent_games,
'ranks':ranks,
- 'summary_stats':summary_stats,
+ 'stat_line':stat_line,
'day_stat_line':day_stat_line,
}
"""
Display the main page information.
"""
- mainindex_data = _main_index_data(request)
-
- # FIXME: code clone, should get these from _main_index_data
- leaderboard_count = 10
- recent_games_count = 20
-
- for i in range(leaderboard_count-len(mainindex_data['top_players'])):
- mainindex_data['top_players'].append(('-', '-', '-'))
-
- for i in range(leaderboard_count-len(mainindex_data['top_servers'])):
- mainindex_data['top_servers'].append(('-', '-', '-'))
-
- for i in range(leaderboard_count-len(mainindex_data['top_maps'])):
- mainindex_data['top_maps'].append(('-', '-', '-'))
-
- return mainindex_data
+ return _main_index_data(request)
def main_index_json(request):
return [{'status':'not implemented'}]
-def top_players_by_time(request):
- current_page = request.params.get('page', 1)
-
- cutoff_days = int(request.registry.settings.\
- get('xonstat.leaderboard_lifetime', 30))
-
- top_players_q = top_players_by_time_q(cutoff_days)
-
- top_players = Page(top_players_q, current_page, items_per_page=25, url=page_url)
-
- top_players.items = [(player_id, html_colors(nick), score) \
- for (player_id, nick, score) in top_players.items]
+def top_players_index(request):
+ try:
+ start = int(request.params.get('start', None))
+ except:
+ start = None
- return {'top_players':top_players}
+ top_players = get_top_players_by_time(20, start)
+ # building a query string
+ query = {}
+ if len(top_players) > 1:
+ query['start'] = top_players[-1].sort_order + 1
-def top_servers_by_players(request):
- current_page = request.params.get('page', 1)
+ return {
+ 'top_players':top_players,
+ 'query':query,
+ 'start':start,
+ }
- cutoff_days = int(request.registry.settings.\
- get('xonstat.leaderboard_lifetime', 30))
- top_servers_q = top_servers_by_players_q(cutoff_days)
+def top_servers_index(request):
+ try:
+ start = int(request.params.get('start', None))
+ except:
+ start = None
- top_servers = Page(top_servers_q, current_page, items_per_page=25, url=page_url)
+ top_servers = get_top_servers_by_games(20, start)
- return {'top_servers':top_servers}
+ # building a query string
+ query = {}
+ if len(top_servers) > 1:
+ query['start'] = top_servers[-1].sort_order + 1
+ return {
+ 'top_servers':top_servers,
+ 'query':query,
+ 'start':start,
+ }
-def top_maps_by_times_played(request):
- current_page = request.params.get('page', 1)
- cutoff_days = int(request.registry.settings.\
- get('xonstat.leaderboard_lifetime', 30))
+def top_maps_index(request):
+ try:
+ start = int(request.params.get('start', None))
+ except:
+ start = None
- top_maps_q = top_maps_by_times_played_q(cutoff_days)
+ top_maps = get_top_maps_by_games(20, start)
- top_maps = Page(top_maps_q, current_page, items_per_page=25, url=page_url)
+ # building a query string
+ query = {}
+ if len(top_maps) > 1:
+ query['start'] = top_maps[-1].sort_order + 1
- return {'top_maps':top_maps}
+ return {
+ 'top_maps':top_maps,
+ 'query':query,
+ 'start':start,
+ }