Skip to content

Commit

Permalink
Merge branch 'fix-game-outcomes' of github.com:Wesmania/server into t…
Browse files Browse the repository at this point in the history
…rueskill-ranks
  • Loading branch information
cleborys committed Sep 20, 2019
2 parents fb69438 + 1577fd2 commit d2d8f9a
Show file tree
Hide file tree
Showing 54 changed files with 1,981 additions and 1,818 deletions.
2 changes: 2 additions & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ humanize = "*"
pytest = "*"
pytest-mock = "*"
pytest-cov = "*"
pytest-asyncio = "*"
coveralls = "*"
mock = "*"
vulture = "*"
asynctest = "*"

[requires]
python_version = "3.6"
484 changes: 90 additions & 394 deletions Pipfile.lock

Large diffs are not rendered by default.

18 changes: 9 additions & 9 deletions server.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,20 +59,20 @@ def signal_handler(_sig, _frame):
signal.signal(signal.SIGTERM, signal_handler)
signal.signal(signal.SIGINT, signal_handler)

engine_fut = asyncio.ensure_future(
server.db.connect_engine(
database = server.db.FAFDatabase(loop)
db_fut = asyncio.ensure_future(
database.connect(
host=DB_SERVER,
port=int(DB_PORT),
user=DB_LOGIN,
password=DB_PASSWORD,
maxsize=10,
db=DB_NAME,
loop=loop
)
)
engine = loop.run_until_complete(engine_fut)
loop.run_until_complete(db_fut)

players_online = PlayerService()
players_online = PlayerService(database)

twilio_nts = None
if TWILIO_ACCOUNT_SID:
Expand All @@ -92,15 +92,16 @@ def signal_handler(_sig, _frame):
event_service, achievement_service
)

games = GameService(players_online, game_stats_service)
ladder_service = LadderService(games)
games = GameService(database, players_online, game_stats_service)
ladder_service = LadderService(database, games)

ctrl_server = loop.run_until_complete(
server.run_control_server(loop, players_online, games)
)

lobby_server = server.run_lobby_server(
address=('', 8001),
database=database,
geoip_service=GeoIpService(),
player_service=players_online,
games=games,
Expand All @@ -117,8 +118,7 @@ def signal_handler(_sig, _frame):
ladder_service.shutdown_queues()

# Close DB connections
engine.close()
loop.run_until_complete(engine.wait_closed())
loop.run_until_complete(database.close())

loop.close()

Expand Down
3 changes: 3 additions & 0 deletions server/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

import aiomeasures

from server.db import FAFDatabase
from . import config as config
from .games.game import GameState, VisibilityState
from .stats.game_stats_service import GameStatsService
Expand Down Expand Up @@ -81,6 +82,7 @@ def encode_queues(queues):

def run_lobby_server(
address: (str, int),
database: FAFDatabase,
player_service: PlayerService,
games: GameService,
loop,
Expand Down Expand Up @@ -137,6 +139,7 @@ def ping_broadcast():

def make_connection() -> LobbyConnection:
return LobbyConnection(
database=database,
geoip=geoip_service,
games=games,
nts_client=nts_client,
Expand Down
36 changes: 0 additions & 36 deletions server/abc/base_game.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
from abc import ABCMeta, abstractmethod
from enum import Enum, IntEnum, unique


Expand All @@ -14,38 +13,3 @@ class GameConnectionState(Enum):
class InitMode(IntEnum):
NORMAL_LOBBY = 0
AUTO_LOBBY = 1


class BaseGame:
__metaclass__ = ABCMeta

@abstractmethod
async def on_game_end(self):
pass # pragma: no cover

async def rate_game(self):
pass # pragma: no cover

@property
@abstractmethod
def init_mode(self):
"""
The initialization mode to use for the Game
:rtype InitMode
:return:
"""
pass # pragma: no cover

@abstractmethod
def teams(self):
"""
A dictionary of lists representing teams
It is of the form:
>>> {
>>> 1: [Player(1), Player(2)],
>>> 2: [Player(3), Player(4)]
>>> }
:return:
"""
pass # pragma: no cover
53 changes: 0 additions & 53 deletions server/abc/base_player.py

This file was deleted.

1 change: 1 addition & 0 deletions server/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@

NEWBIE_BASE_MEAN = int(os.getenv('NEWBIE_BASE_MEAN', 500))
NEWBIE_MIN_GAMES = int(os.getenv('NEWBIE_MIN_GAMES', 10))
TOP_PLAYER_MIN_RATING = int(os.getenv('TOP_PLAYER_MIN_RATING', 1600))

TWILIO_ACCOUNT_SID = os.getenv("TWILIO_ACCOUNT_SID", "")
TWILIO_TOKEN = os.getenv("TWILIO_TOKEN", "")
Expand Down
54 changes: 29 additions & 25 deletions server/db/__init__.py
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
from aiomysql.sa import create_engine

engine = None

class FAFDatabase:
def __init__(self, loop):
self._loop = loop
self.engine = None

def set_engine(engine_):
"""
Set the globally used engine to the given argument
"""
global engine
engine = engine_
async def connect(self, host='localhost', port=3306, user='root',
password='', db='faf_test', minsize=1, maxsize=1,
echo=True):
if self.engine is not None:
raise ValueError("DB is already connected!")
self.engine = await create_engine(
host=host,
port=port,
user=user,
password=password,
db=db,
autocommit=True,
loop=self._loop,
minsize=minsize,
maxsize=maxsize,
echo=echo
)

def acquire(self):
return self.engine.acquire()

async def connect_engine(
loop, host='localhost', port=3306, user='root', password='', db='faf_test',
minsize=1, maxsize=1, echo=True
):
engine = await create_engine(
host=host,
port=port,
user=user,
password=password,
db=db,
autocommit=True,
loop=loop,
minsize=minsize,
maxsize=maxsize,
echo=echo
)
async def close(self):
if self.engine is None:
return

set_engine(engine)
return engine
self.engine.close()
await self.engine.wait_closed()
self.engine = None
10 changes: 6 additions & 4 deletions server/game_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
from typing import Dict, List, Optional, Union, ValuesView

import aiocron
import server.db as db
from server.db import FAFDatabase
from server import GameState, VisibilityState
from server.decorators import with_logger
from server.games import CoopGame, CustomGame, FeaturedMod, LadderGame
Expand All @@ -16,7 +16,8 @@ class GameService:
"""
Utility class for maintaining lifecycle of games
"""
def __init__(self, player_service, game_stats_service):
def __init__(self, database: FAFDatabase, player_service, game_stats_service):
self._db = database
self._dirty_games = set()
self._dirty_queues = set()
self.player_service = player_service
Expand Down Expand Up @@ -45,7 +46,7 @@ def __init__(self, player_service, game_stats_service):
self._update_cron = aiocron.crontab('*/10 * * * *', func=self.update_data)

async def initialise_game_counter(self):
async with db.engine.acquire() as conn:
async with self._db.acquire() as conn:
# InnoDB, unusually, doesn't allow insertion of values greater than the next expected
# value into an auto_increment field. We'd like to do that, because we no longer insert
# games into the database when they don't start, so game ids aren't contiguous (as
Expand All @@ -66,7 +67,7 @@ async def update_data(self):
Loads from the database the mostly-constant things that it doesn't make sense to query every
time we need, but which can in principle change over time.
"""
async with db.engine.acquire() as conn:
async with self._db.acquire() as conn:
result = await conn.execute("SELECT `id`, `gamemod`, `name`, description, publish, `order` FROM game_featuredMods")

async for row in result:
Expand Down Expand Up @@ -126,6 +127,7 @@ def create_game(
"""
game_id = self.create_uid()
args = {
"database": self._db,
"id_": game_id,
"host": host,
"name": name,
Expand Down
19 changes: 10 additions & 9 deletions server/gameconnection.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import asyncio

import server.db as db
from server.db import FAFDatabase
from sqlalchemy import text, select

from .abc.base_game import GameConnectionState
Expand All @@ -23,6 +23,7 @@ class GameConnection(GpgNetServerProtocol):

def __init__(
self,
database: FAFDatabase,
game: Game,
player: Player,
protocol: QDataStreamProtocol,
Expand All @@ -34,6 +35,7 @@ def __init__(
Construct a new GameConnection
"""
super().__init__()
self._db = database
self._logger.debug('GameConnection initializing')

self.protocol = protocol
Expand Down Expand Up @@ -211,7 +213,7 @@ async def handle_game_mods(self, mode, args):
elif mode == "uids":
uids = str(args).split()
self.game.mods = {uid: "Unknown sim mod" for uid in uids}
async with db.engine.acquire() as conn:
async with self._db.acquire() as conn:
result = await conn.execute(
text("SELECT `uid`, `name` from `table_mod` WHERE `uid` in :ids"),
ids=tuple(uids))
Expand Down Expand Up @@ -255,7 +257,7 @@ async def handle_game_result(self, army, result):
self.finished_sim = True
await self.game.check_sim_end()

await self.game.add_result(self.player, army, result[0], int(result[1]))
await self.game.add_result(self.player.id, army, result[0], int(result[1]))
except (KeyError, ValueError): # pragma: no cover
self._logger.warning("Invalid result for %s reported: %s", army, result)

Expand All @@ -267,7 +269,7 @@ async def handle_operation_complete(self, army, secondary, delta):
return

secondary, delta = int(secondary), str(delta)
async with db.engine.acquire() as conn:
async with self._db.acquire() as conn:
# FIXME: Resolve used map earlier than this
result = await conn.execute(
"SELECT `id` FROM `coop_map` WHERE `filename` = %s",
Expand Down Expand Up @@ -301,9 +303,8 @@ async def handle_teamkill_report(self, gametime, reporter_id, reporter_name, tea
:param teamkiller_id: teamkiller id
:param teamkiller_name: teamkiller nickname - Used as a failsafe in case ID is wrong
"""

async with db.engine.acquire() as conn:


async with self._db.acquire() as conn:
"""
Sometime the game sends a wrong ID - but a correct player name
We need to make sure the player ID is correct before pursuing
Expand Down Expand Up @@ -379,7 +380,7 @@ async def handle_teamkill_happened(self, gametime, victim_id, victim_name, teamk
self._logger.debug("Ignoring teamkill for AI player")
return

async with db.engine.acquire() as conn:
async with self._db.acquire() as conn:
await conn.execute(
""" INSERT INTO `teamkills` (`teamkiller`, `victim`, `game_id`, `gametime`)
VALUES (%s, %s, %s, %s)""",
Expand Down Expand Up @@ -435,7 +436,7 @@ async def handle_game_state(self, state):
await self.game.launch()

if len(self.game.mods.keys()) > 0:
async with db.engine.acquire() as conn:
async with self._db.acquire() as conn:
uids = list(self.game.mods.keys())
await conn.execute(text(
""" UPDATE mod_stats s JOIN mod_version v ON v.mod_id = s.mod_id
Expand Down
Loading

0 comments on commit d2d8f9a

Please sign in to comment.