Esempio n. 1
0
    def delete(self, player_id):
        if player_id != current_user[
                "player_id"] and "service" not in current_user["roles"]:
            abort(httplib.BAD_REQUEST, message="This is not your player")

        args = self.delete_args.parse_args()
        force = args.force

        log.info("Removing player %d from the match queue", player_id)

        my_matchqueueplayer = g.db.query(MatchQueuePlayer) \
            .filter(MatchQueuePlayer.player_id == player_id) \
            .order_by(-MatchQueuePlayer.id).first()

        if not my_matchqueueplayer:
            abort(httplib.NOT_FOUND,
                  message="Player is not in the queue",
                  code="player_not_in_queue")

        if my_matchqueueplayer.status == "matched" and not force:
            abort(httplib.BAD_REQUEST,
                  message="Player has already been matched",
                  code="player_already_matched")

        g.db.delete(my_matchqueueplayer)
        g.db.commit()

        return json_response("Player is no longer in the match queue",
                             httplib.OK)
Esempio n. 2
0
    def get(self, player_id, journal_id):
        """
        Get a specific journal entry for the player
        """
        can_edit_player(player_id)

        entry = get_journal_entry(player_id, journal_id)
        if not entry.first():
            return json_response("Journal entry not found", httplib.NOT_FOUND)
        ret = entry.first().as_dict()
        return ret
Esempio n. 3
0
    def delete(self, client_id):
        """
        Deregister an already registered client. Should return status 200 if successful.
        """
        ret = self.validate_call(client_id)
        if ret:
            return ret
        client = g.db.query(Client).get(client_id)
        if not client or client.status == "deleted":
            abort(httplib.NOT_FOUND)
        client.heartbeat = utcnow()
        client.num_heartbeats += 1
        client.status = "deleted"
        g.db.commit()

        log.info("Client %s from player %s has been unregistered",
                 client_id, current_user["player_id"])

        return json_response("Client has been closed. Please terminate the client.",
                             httplib.OK)
Esempio n. 4
0
    def post(self, player_id):
        """
        Add a journal entry
        """
        if not can_edit_player(player_id):
            abort(httplib.METHOD_NOT_ALLOWED, message="That is not your player!")

        args_list = request.json
        if not isinstance(args_list, list):
            raise RuntimeError("Arguments should be a list")
        for a in args_list:
            if "journal_id" not in a:
                abort(httplib.BAD_REQUEST)
        ret = []
        now = datetime.datetime.utcnow()
        MAX_DRIFT = 60
        args_list.sort(key=itemgetter('journal_id'))
        client_current_time = args_list[0].get("client_current_time")
        if not client_current_time:
            log.warning("Client is uploading journal entries without a client_current_time")
        else:
            client_current_time = parser.parse(client_current_time)
            diff = (client_current_time.replace(tzinfo=None) - now).total_seconds()
            if abs(diff) > MAX_DRIFT:
                log.warning("Client's clock is %.0f seconds out of sync. "
                            "Client system time: '%s', Server time: '%s'",
                            diff, client_current_time, now)
        for args in args_list:
            # Special handling if this is a rollback event.
            # We mark all journal entries higher than the event to rollback to
            # as deleted (as an optimization) and then add the rollback event itself.
            if "rollback_to_journal_id" in args:
                to_journal_id = int(args.get("rollback_to_journal_id"))
                # TODO: Check if there are any gamestates persisted after the id
                gamestate = get_player_gamestate(player_id)
                if not gamestate:
                    log.warning("Player is rebasing journal entries but doesn't"
                                "have any gamestate.")

                elif gamestate.journal_id > to_journal_id:
                    return json_response("Journal has already been persisted into home base!",
                                         httplib.BAD_REQUEST)

                entry = get_journal_entry(player_id, to_journal_id)
                if not entry.first():
                    log.warning("Rolling back to journal entry %s which doesn't exist")
                elif entry.first().deleted:
                    log.warning("Rolling back to journal entry %s which has been rolled back")

                g.db.query(PlayerJournal).filter(PlayerJournal.player_id == player_id,
                                                 PlayerJournal.journal_id > to_journal_id) \
                                         .update({"deleted": True})

            # report if the client's clock is out of sync with the server
            timestamp = parser.parse(args["timestamp"])
            diff = (timestamp.replace(tzinfo=None) - now).total_seconds()
            if abs(diff) > MAX_DRIFT:
                log.info("Client is sending journal info for journal entry %s '%s' which "
                         "is %.0f seconds out of sync. "
                         "Client journal timestamp: '%s', Server timestamp: '%s'",
                         args["journal_id"], args["action"], diff, args["timestamp"], now)

            try:
                journal = write_journal(player_id, args["action"], args["journal_id"],
                                        args["timestamp"],
                                        details=args.get("details"), steps=args.get("steps"),
                                        actor_id=current_user["player_id"])
            except JournalError as e:
                # TODO: We now reject the journal entry and subsequent entries instead of
                # rolling the entire thing back. Is that what we want?
                log.warning("Error writing to journal. Rejecting entry. Error was: %s", e)
                abort(httplib.BAD_REQUEST, description=e.message)

            ret.append({"journal_id": journal["journal_id"],
                        "url": url_for("journal.entry",
                                       player_id=player_id,
                                       journal_id=journal["journal_id"])
                        })
        return ret, httplib.CREATED
Esempio n. 5
0
    def put(self, player_id, namespace):
        """
        Upload the gamestate state to the server
        """
        can_edit_player(player_id)

        args = request.json
        data = args["gamestate"]
        journal_id = None
        if args.get("journal_id"):
            journal_id = int(args["journal_id"])

        if journal_id:
            journal_row = g.db.query(PlayerJournal) \
                .filter(PlayerJournal.player_id == player_id,
                        PlayerJournal.journal_id == journal_id,
                        PlayerJournal.deleted != True) \
                .first()
            if not journal_row:
                # Note: this might happen normally unless we serialize on the
                # client to ensure all journal entries
                # are acked before sending up the new state
                msg = "Journal entry %s for player %s not found!" % (
                    journal_id, player_id)
                log.warning(msg)
                return json_response(msg, httplib.BAD_REQUEST)

        gamestate = g.db.query(GameState)\
            .filter(GameState.player_id == player_id, GameState.namespace == namespace) \
            .order_by(-GameState.gamestate_id).first()

        if gamestate:
            if journal_id and journal_id <= gamestate.journal_id:
                # TODO: Raise here?
                log.warning(
                    "Writing a new gamestate with an older journal_id, %s "
                    "than the current one",
                    journal_id,
                    extra=gamestate.as_dict())
            gamestate.version += 1
            gamestate.data = data
            gamestate.journal_id = journal_id
            log.info(
                "Updated gamestate for player %s to version %s. journal_id = %s",
                player_id, gamestate.version, journal_id)
        else:
            gamestate = GameState(player_id=player_id,
                                  data=data,
                                  journal_id=journal_id,
                                  namespace=namespace)
            g.db.add(gamestate)
            g.db.flush()
            log.info("Added new gamestate for player")

        # write new gamestate to the history table for safe keeping
        gamestatehistory_row = GameStateHistory(
            player_id=player_id,
            version=gamestate.version,
            data=gamestate.data,
            namespace=gamestate.namespace,
            journal_id=gamestate.journal_id)
        g.db.add(gamestatehistory_row)
        g.db.flush()

        gamestatehistory_id = gamestatehistory_row.gamestatehistory_id
        gamestate.gamestatehistory_id = gamestatehistory_id
        g.db.commit()

        return gamestate.as_dict()