aboutsummaryrefslogtreecommitdiff
path: root/diplomacy/client/channel.py
diff options
context:
space:
mode:
Diffstat (limited to 'diplomacy/client/channel.py')
-rw-r--r--diplomacy/client/channel.py134
1 files changed, 81 insertions, 53 deletions
diff --git a/diplomacy/client/channel.py b/diplomacy/client/channel.py
index 0403e7f..146d5e3 100644
--- a/diplomacy/client/channel.py
+++ b/diplomacy/client/channel.py
@@ -15,6 +15,7 @@
# with this program. If not, see <https://www.gnu.org/licenses/>.
# ==============================================================================
""" Channel
+
- The channel object represents an authenticated connection over a socket.
- It has a token that it sends with every request to authenticate itself.
"""
@@ -23,21 +24,26 @@ import logging
from tornado import gen
from diplomacy.communication import requests
-from diplomacy.utils import strings
+from diplomacy.utils import strings, common
LOGGER = logging.getLogger(__name__)
-def req_fn(request_class, local_req_fn=None, **request_args):
+def _req_fn(request_class, local_req_fn=None, **request_args):
""" Create channel request method that sends request with channel token.
+
:param request_class: class of request to send with channel request method.
:param local_req_fn: (optional) Channel method to use locally to try retrieving a data
instead of sending a request. If provided, local_req_fn is called with request args:
+
- if it returns anything else than None, then returned data is returned by channel request method.
- else, request class is still sent and channel request method follows standard path
(request sent, response received, response handler called and final handler result returned).
+
:param request_args: arguments to pass to request class to create the request object.
:return: a Channel method.
"""
+ str_params = (', '.join('%s=%s' % (key, common.to_string(value))
+ for (key, value) in sorted(request_args.items()))) if request_args else ''
@gen.coroutine
def func(self, game_object=None, **kwargs):
@@ -67,29 +73,51 @@ def req_fn(request_class, local_req_fn=None, **request_args):
request = request_class(**kwargs)
return (yield self.connection.send(request, game_object))
+ func.__request_name__ = request_class.__name__
+ func.__request_params__ = str_params
+ func.__doc__ = """
+ Send request :class:`.%(request_name)s`%(with_params)s``kwargs``.
+ Return response data returned by server for this request.
+ See :class:`.%(request_name)s` about request parameters and response.
+ """ % {'request_name': request_class.__name__,
+ 'with_params': ' with forced parameters ``(%s)`` and additional request parameters '
+ % str_params if request_args else ' with request parameters '}
return func
-class Channel():
+class Channel:
""" Channel - Represents an authenticated connection over a physical socket """
+ # pylint: disable=too-few-public-methods
__slots__ = ['connection', 'token', 'game_id_to_instances', '__weakref__']
def __init__(self, connection, token):
""" Initialize a channel.
+
+ Properties:
+
+ - **connection**: :class:`.Connection` object from which this channel originated.
+ - **token**: Channel token, used to identify channel on server.
+ - **game_id_to_instances**: Dictionary mapping a game ID to :class:`.NetworkGame` objects loaded for this
+ game. Each :class:`.NetworkGame` has a specific role, which is either an observer role, an omniscient
+ role, or a power (player) role. Network games for a specific game ID are managed within a
+ :class:`.GameInstancesSet`, which makes sure that there will be at most 1 :class:`.NetworkGame` instance
+ per possible role.
+
:param connection: a Connection object.
:param token: Channel token.
- :type connection: diplomacy.Connection
+ :type connection: diplomacy.client.connection.Connection
+ :type token: str
"""
self.connection = connection
self.token = token
self.game_id_to_instances = {} # {game id => GameInstances}
- def local_join_game(self, **kwargs):
+ def _local_join_game(self, **kwargs):
""" Look for a local game with given kwargs intended to be used to build a JoinGame request.
Return None if no local game found, else local game found.
- Game is identified with game ID and power name (optional).
+ Game is identified with game ID **(required)** and power name *(optional)*.
If power name is None, we look for a "special" game (observer or omniscient game)
- loaded locally. Note that there is at most 1 special game per channel + game ID:
- either observer or omniscient, not both.
+ loaded locally. Note that there is at most 1 special game per (channel + game ID)
+ couple: either observer or omniscient, not both.
"""
game_id = kwargs[strings.GAME_ID]
power_name = kwargs.get(strings.POWER_NAME, None)
@@ -103,54 +131,54 @@ class Channel():
# Public channel API.
# ===================
- create_game = req_fn(requests.CreateGame)
- get_available_maps = req_fn(requests.GetAvailableMaps)
- get_playable_powers = req_fn(requests.GetPlayablePowers)
- join_game = req_fn(requests.JoinGame, local_req_fn=local_join_game)
- join_powers = req_fn(requests.JoinPowers)
- list_games = req_fn(requests.ListGames)
- get_games_info = req_fn(requests.GetGamesInfo)
+ create_game = _req_fn(requests.CreateGame)
+ get_available_maps = _req_fn(requests.GetAvailableMaps)
+ get_playable_powers = _req_fn(requests.GetPlayablePowers)
+ join_game = _req_fn(requests.JoinGame, local_req_fn=_local_join_game)
+ join_powers = _req_fn(requests.JoinPowers)
+ list_games = _req_fn(requests.ListGames)
+ get_games_info = _req_fn(requests.GetGamesInfo)
+ get_dummy_waiting_powers = _req_fn(requests.GetDummyWaitingPowers)
# User Account API.
- delete_account = req_fn(requests.DeleteAccount)
- logout = req_fn(requests.Logout)
+ delete_account = _req_fn(requests.DeleteAccount)
+ logout = _req_fn(requests.Logout)
# Admin / Moderator API.
- make_omniscient = req_fn(requests.SetGrade, grade=strings.OMNISCIENT, grade_update=strings.PROMOTE)
- remove_omniscient = req_fn(requests.SetGrade, grade=strings.OMNISCIENT, grade_update=strings.DEMOTE)
- promote_administrator = req_fn(requests.SetGrade, grade=strings.ADMIN, grade_update=strings.PROMOTE)
- demote_administrator = req_fn(requests.SetGrade, grade=strings.ADMIN, grade_update=strings.DEMOTE)
- promote_moderator = req_fn(requests.SetGrade, grade=strings.MODERATOR, grade_update=strings.PROMOTE)
- demote_moderator = req_fn(requests.SetGrade, grade=strings.MODERATOR, grade_update=strings.DEMOTE)
-
- # ================
- # Public game API.
- # ================
-
- get_dummy_waiting_powers = req_fn(requests.GetDummyWaitingPowers)
- get_phase_history = req_fn(requests.GetPhaseHistory)
- leave_game = req_fn(requests.LeaveGame)
- send_game_message = req_fn(requests.SendGameMessage)
- set_orders = req_fn(requests.SetOrders)
-
- clear_centers = req_fn(requests.ClearCenters)
- clear_orders = req_fn(requests.ClearOrders)
- clear_units = req_fn(requests.ClearUnits)
-
- wait = req_fn(requests.SetWaitFlag, wait=True)
- no_wait = req_fn(requests.SetWaitFlag, wait=False)
- vote = req_fn(requests.Vote)
- save = req_fn(requests.SaveGame)
- synchronize = req_fn(requests.Synchronize)
+ make_omniscient = _req_fn(requests.SetGrade, grade=strings.OMNISCIENT, grade_update=strings.PROMOTE)
+ remove_omniscient = _req_fn(requests.SetGrade, grade=strings.OMNISCIENT, grade_update=strings.DEMOTE)
+ promote_administrator = _req_fn(requests.SetGrade, grade=strings.ADMIN, grade_update=strings.PROMOTE)
+ demote_administrator = _req_fn(requests.SetGrade, grade=strings.ADMIN, grade_update=strings.DEMOTE)
+ promote_moderator = _req_fn(requests.SetGrade, grade=strings.MODERATOR, grade_update=strings.PROMOTE)
+ demote_moderator = _req_fn(requests.SetGrade, grade=strings.MODERATOR, grade_update=strings.DEMOTE)
+
+ # ====================================================================
+ # Game API. Intended to be called by NetworkGame object, not directly.
+ # ====================================================================
+
+ _get_phase_history = _req_fn(requests.GetPhaseHistory)
+ _leave_game = _req_fn(requests.LeaveGame)
+ _send_game_message = _req_fn(requests.SendGameMessage)
+ _set_orders = _req_fn(requests.SetOrders)
+
+ _clear_centers = _req_fn(requests.ClearCenters)
+ _clear_orders = _req_fn(requests.ClearOrders)
+ _clear_units = _req_fn(requests.ClearUnits)
+
+ _wait = _req_fn(requests.SetWaitFlag, wait=True)
+ _no_wait = _req_fn(requests.SetWaitFlag, wait=False)
+ _vote = _req_fn(requests.Vote)
+ _save = _req_fn(requests.SaveGame)
+ _synchronize = _req_fn(requests.Synchronize)
# Admin / Moderator API.
- delete_game = req_fn(requests.DeleteGame)
- kick_powers = req_fn(requests.SetDummyPowers)
- set_state = req_fn(requests.SetGameState)
- process = req_fn(requests.ProcessGame)
- query_schedule = req_fn(requests.QuerySchedule)
- start = req_fn(requests.SetGameStatus, status=strings.ACTIVE)
- pause = req_fn(requests.SetGameStatus, status=strings.PAUSED)
- resume = req_fn(requests.SetGameStatus, status=strings.ACTIVE)
- cancel = req_fn(requests.SetGameStatus, status=strings.CANCELED)
- draw = req_fn(requests.SetGameStatus, status=strings.COMPLETED)
+ _delete_game = _req_fn(requests.DeleteGame)
+ _kick_powers = _req_fn(requests.SetDummyPowers)
+ _set_state = _req_fn(requests.SetGameState)
+ _process = _req_fn(requests.ProcessGame)
+ _query_schedule = _req_fn(requests.QuerySchedule)
+ _start = _req_fn(requests.SetGameStatus, status=strings.ACTIVE)
+ _pause = _req_fn(requests.SetGameStatus, status=strings.PAUSED)
+ _resume = _req_fn(requests.SetGameStatus, status=strings.ACTIVE)
+ _cancel = _req_fn(requests.SetGameStatus, status=strings.CANCELED)
+ _draw = _req_fn(requests.SetGameStatus, status=strings.COMPLETED)