]> de.git.xonotic.org Git - xonotic/xonstat.git/blobdiff - xonstat/views/submission.py
Remove the try-catch block here. It isn't needed.
[xonotic/xonstat.git] / xonstat / views / submission.py
index 1b7417f78f1124eeeda6aa9487e1bbf0025c2076..2e89c15d5379d051232f889c623566a9ff85edce 100644 (file)
@@ -328,18 +328,22 @@ def is_supported_gametype(submission):
     return is_supported
 
 
-def get_remote_addr(request):
-    """Get the Xonotic server's IP address"""
-    if 'X-Forwarded-For' in request.headers:
-        return request.headers['X-Forwarded-For']
-    else:
-        return request.remote_addr
+def has_minimum_real_players(settings, submission):
+    """
+    Determines if the submission has enough human players to store in the database. The minimum
+    setting comes from the config file under the setting xonstat.minimum_real_players.
+    """
+    try:
+        minimum_required_players = int(settings.get("xonstat.minimum_required_players"))
+    except:
+        minimum_required_players = 2
+
+    return len(submission.human_players) >= minimum_required_players
 
 
-def do_precondition_checks(request, game_meta, raw_players):
-    """Precondition checks for ALL gametypes.
-       These do not require a database connection."""
-    if not has_required_metadata(game_meta):
+def do_precondition_checks(settings, submission):
+    """Precondition checks for ALL gametypes. These do not require a database connection."""
+    if not has_required_metadata(submission):
         msg = "Missing required game metadata"
         log.debug(msg)
         raise pyramid.httpexceptions.HTTPUnprocessableEntity(
@@ -347,9 +351,7 @@ def do_precondition_checks(request, game_meta, raw_players):
             content_type="text/plain"
         )
 
-    try:
-        version = int(game_meta['V'])
-    except:
+    if submission.version is None:
         msg = "Invalid or incorrect game metadata provided"
         log.debug(msg)
         raise pyramid.httpexceptions.HTTPUnprocessableEntity(
@@ -357,15 +359,15 @@ def do_precondition_checks(request, game_meta, raw_players):
             content_type="text/plain"
         )
 
-    if not is_supported_gametype(game_meta['G'], version):
-        msg = "Unsupported game type ({})".format(game_meta['G'])
+    if not is_supported_gametype(submission):
+        msg = "Unsupported game type ({})".format(submission.game_type_cd)
         log.debug(msg)
         raise pyramid.httpexceptions.HTTPOk(
             body=msg,
             content_type="text/plain"
         )
 
-    if not has_minimum_real_players(request.registry.settings, raw_players):
+    if not has_minimum_real_players(settings, submission):
         msg = "Not enough real players"
         log.debug(msg)
         raise pyramid.httpexceptions.HTTPOk(
@@ -373,7 +375,7 @@ def do_precondition_checks(request, game_meta, raw_players):
             content_type="text/plain"
         )
 
-    if is_blank_game(game_meta['G'], raw_players):
+    if is_blank_game(submission):
         msg = "Blank game"
         log.debug(msg)
         raise pyramid.httpexceptions.HTTPOk(
@@ -382,58 +384,22 @@ def do_precondition_checks(request, game_meta, raw_players):
         )
 
 
-def num_real_players(player_events):
-    """
-    Returns the number of real players (those who played
-    and are on the scoreboard).
-    """
-    real_players = 0
-
-    for events in player_events:
-        if is_real_player(events) and played_in_game(events):
-            real_players += 1
-
-    return real_players
-
-
-def has_minimum_real_players(settings, player_events):
-    """
-    Determines if the collection of player events has enough "real" players
-    to store in the database. The minimum setting comes from the config file
-    under the setting xonstat.minimum_real_players.
-    """
-    flg_has_min_real_players = True
-
-    try:
-        minimum_required_players = int(
-                settings['xonstat.minimum_required_players'])
-    except:
-        minimum_required_players = 2
-
-    real_players = num_real_players(player_events)
-
-    if real_players < minimum_required_players:
-        flg_has_min_real_players = False
-
-    return flg_has_min_real_players
+def get_remote_addr(request):
+    """Get the Xonotic server's IP address"""
+    if 'X-Forwarded-For' in request.headers:
+        return request.headers['X-Forwarded-For']
+    else:
+        return request.remote_addr
 
 
 def should_do_weapon_stats(game_type_cd):
     """True of the game type should record weapon stats. False otherwise."""
-    if game_type_cd in 'cts':
-        return False
-    else:
-        return True
+    return game_type_cd not in {'cts'}
 
 
 def gametype_elo_eligible(game_type_cd):
     """True of the game type should process Elos. False otherwise."""
-    elo_game_types = ('duel', 'dm', 'ca', 'ctf', 'tdm', 'ka', 'ft')
-
-    if game_type_cd in elo_game_types:
-        return True
-    else:
-        return False
+    return game_type_cd in {'duel', 'dm', 'ca', 'ctf', 'tdm', 'ka', 'ft'}
 
 
 def register_new_nick(session, player, new_nick):
@@ -776,7 +742,7 @@ def create_default_game_stat(session, game_type_cd):
     return pgstat
 
 
-def create_game_stat(session, game_meta, game, server, gmap, player, events):
+def create_game_stat(session, game, gmap, player, events):
     """Game stats handler for all game types"""
 
     game_type_cd = game.game_type_cd
@@ -922,7 +888,7 @@ def create_team_stat(session, game, events):
     return teamstat
 
 
-def create_weapon_stats(session, game_meta, game, player, pgstat, events):
+def create_weapon_stats(session, version, game, player, pgstat, events):
     """Weapon stats handler for all game types"""
     pwstats = []
 
@@ -930,7 +896,6 @@ def create_weapon_stats(session, game_meta, game, player, pgstat, events):
     # To counteract this we divide the data by 2 only for
     # POSTs coming from version 1.
     try:
-        version = int(game_meta['V'])
         if version == 1:
             is_doubled = True
             log.debug('NOTICE: found a version 1 request, halving the weapon stats...')
@@ -1019,88 +984,66 @@ def submit_stats(request):
                 "----- END REQUEST BODY -----\n\n")
 
         (idfp, status) = verify_request(request)
-        (game_meta, raw_players, raw_teams) = parse_stats_submission(request.body)
-        revision = game_meta.get('R', 'unknown')
-        duration = game_meta.get('D', None)
+        submission = Submission(request.body, request.headers)
 
-        # only players present at the end of the match are eligible for stats
-        raw_players = filter(played_in_game, raw_players)
-
-        do_precondition_checks(request, game_meta, raw_players)
-
-        # the "duel" gametype is fake
-        if len(raw_players) == 2 \
-            and num_real_players(raw_players) == 2 \
-            and game_meta['G'] == 'dm':
-            game_meta['G'] = 'duel'
+        do_precondition_checks(request.registry.settings, submission)
 
         #----------------------------------------------------------------------
         # Actual setup (inserts/updates) below here
         #----------------------------------------------------------------------
         session = DBSession()
 
-        game_type_cd = game_meta['G']
-
         # All game types create Game, Server, Map, and Player records
         # the same way.
         server = get_or_create_server(
-                session      = session,
-                hashkey      = idfp,
-                name         = game_meta['S'],
-                revision     = revision,
-                ip_addr      = get_remote_addr(request),
-                port         = game_meta.get('U', None),
-                impure_cvars = game_meta.get('C', 0))
-
-        gmap = get_or_create_map(
-                session = session,
-                name    = game_meta['M'])
+            session=session,
+            hashkey=idfp,
+            name=submission.server_name,
+            revision=submission.revision,
+            ip_addr=get_remote_addr(request),
+            port=submission.port_number,
+            impure_cvars=submission.impure_cvar_changes
+        )
+
+        gmap = get_or_create_map(session, submission.map_name)
 
         game = create_game(
-                session      = session,
-                start_dt     = datetime.datetime.utcnow(),
-                server_id    = server.server_id,
-                game_type_cd = game_type_cd,
-                map_id       = gmap.map_id,
-                match_id     = game_meta['I'],
-                duration     = duration,
-                mod          = game_meta.get('O', None))
+            session=session,
+            start_dt=datetime.datetime.utcnow(),
+            server_id=server.server_id,
+            game_type_cd=submission.game_type_cd,
+            map_id=gmap.map_id,
+            match_id=submission.match_id,
+            duration=submission.duration,
+            mod=submission.mod
+        )
 
         # keep track of the players we've seen
         player_ids = []
         pgstats = []
         hashkeys = {}
-        for events in raw_players:
-            player = get_or_create_player(
-                session = session,
-                hashkey = events['P'],
-                nick    = events.get('n', None))
-
-            pgstat = create_game_stat(session, game_meta, game, server,
-                    gmap, player, events)
+        for events in submission.humans + submission.bots:
+            player = get_or_create_player(session, events['P'], events.get('n', None))
+            pgstat = create_game_stat(session, game, gmap, player, events)
             pgstats.append(pgstat)
 
             if player.player_id > 1:
-                anticheats = create_anticheats(session, pgstat, game, player, events)
+                create_anticheats(session, pgstat, game, player, events)
 
             if player.player_id > 2:
                 player_ids.append(player.player_id)
                 hashkeys[player.player_id] = events['P']
 
-            if should_do_weapon_stats(game_type_cd) and player.player_id > 1:
-                pwstats = create_weapon_stats(session, game_meta, game, player,
-                        pgstat, events)
+            if should_do_weapon_stats(submission.game_type_cd) and player.player_id > 1:
+                create_weapon_stats(session, submission.version, game, player, pgstat, events)
 
         # store them on games for easy access
         game.players = player_ids
 
-        for events in raw_teams:
-            try:
-                teamstat = create_team_stat(session, game, events)
-            except Exception as e:
-                raise e
+        for events in submission.teams:
+            create_team_stat(session, game, events)
 
-        if server.elo_ind and gametype_elo_eligible(game_type_cd):
+        if server.elo_ind and gametype_elo_eligible(submission.game_type_cd):
             ep = EloProcessor(session, game, pgstats)
             ep.save(session)
 
@@ -1108,20 +1051,20 @@ def submit_stats(request):
         log.debug('Success! Stats recorded.')
 
         # ranks are fetched after we've done the "real" processing
-        ranks = get_ranks(session, player_ids, game_type_cd)
+        ranks = get_ranks(session, player_ids, submission.game_type_cd)
 
         # plain text response
         request.response.content_type = 'text/plain'
 
         return {
-                "now"        : calendar.timegm(datetime.datetime.utcnow().timetuple()),
-                "server"     : server,
-                "game"       : game,
-                "gmap"       : gmap,
-                "player_ids" : player_ids,
-                "hashkeys"   : hashkeys,
-                "elos"       : ep.wip,
-                "ranks"      : ranks,
+                "now": calendar.timegm(datetime.datetime.utcnow().timetuple()),
+                "server": server,
+                "game": game,
+                "gmap": gmap,
+                "player_ids": player_ids,
+                "hashkeys": hashkeys,
+                "elos": ep.wip,
+                "ranks": ranks,
         }
 
     except Exception as e: