laneya

multiplayer roguelike game
git clone https://git.ce9e.org/laneya.git

commit
7efd7accda07fa66c1286d38d4815407e1402c6a
parent
39eca6b4579dbd97ffcb2f364ec86740e6762312
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2018-08-03 10:52
refactor promises

Diffstat

R laneya/deferred.py -> laneya/promise.py 125 +++++++++++++++++++------------------------------------------
M laneya/protocol.py 26 +++++++++++++-------------

2 files changed, 52 insertions, 99 deletions


diff --git a/laneya/deferred.py b/laneya/promise.py

@@ -22,65 +22,27 @@ RESOLVED = 1
   22    22 REJECTED = 2
   23    23 
   24    24 
   25    -1 class AlreadyDoneError(Exception):
   26    -1     """The deferred has already been resolved or rejected."""
   27    -1 
   28    -1 
   29    -1 class Deferred(object):
   30    -1     def __init__(self):
   31    -1         self.promise = Promise()
   32    -1 
   33    -1     def resolve(self, value, silent=False, status=RESOLVED):
   34    -1         """Resolve the deferred.
   35    -1 
   36    -1         All success callbacks that are registered on the promise will be
   37    -1         executed with ``value``.
   38    -1 
   39    -1         All success callbacks that will be registered on the promise will be
   40    -1         executed immediately.
   41    -1 
   42    -1         Throws :py:exc:`AlreadyDoneError` if already resolved/rejected.
   43    -1 
   44    -1         """
   45    -1         if self.promise._status == OPEN:
   46    -1             self.promise._status = status
   47    -1             self.promise._value = value
   48    -1             for d, callback, errback in self.promise._children:
   49    -1                 if status == RESOLVED:
   50    -1                     callback(value).then(d.resolve, d.reject)
   51    -1                 else:  # rejected
   52    -1                     errback(value).then(d.resolve, d.reject)
   53    -1         elif not silent:
   54    -1             raise AlreadyDoneError
   55    -1 
   56    -1     def reject(self, value, silent=False):
   57    -1         """Reject the deferred.
   58    -1 
   59    -1         Works execatly like :py:meth:`resolve`, only that it triggers the
   60    -1         execution of error callbacks.
   61    -1 
   62    -1         """
   63    -1         return self.resolve(value, silent=silent, status=REJECTED)
   64    -1 
   65    -1 
   66    25 class Promise(object):
   67    26     def __init__(self):
   68    27         self._children = []
   69    28         self._status = OPEN
   70    29         self._value = None
   71    30 
   72    -1     def then(self, callback, errback=None):
   73    -1         """Register callbacks.
   74    -1 
   75    -1         The registered callbacks will be executed as soon as the associated
   76    -1         deferred has either been resolved or rejected.  If it already has been,
   77    -1         the corresponding callback is executed immediately.
   -1    31     def resolve(self, value):
   -1    32         if self._status == OPEN:
   -1    33             self._status = RESOLVED
   -1    34             self._value = value
   -1    35             for d, callback, errback in self._children:
   -1    36                 callback(value).then(d.resolve, d.reject)
   78    37 
   79    -1         :py:meth:`then` always returns a promise which will be resolved with
   80    -1         the result of the callback.  If the callback raises an exception, the
   81    -1         promise is rejected.
   -1    38     def reject(self, value, silent=False):
   -1    39         if self._status == OPEN:
   -1    40             self._status = REJECTED
   -1    41             self._value = value
   -1    42             for d, callback, errback in self._children:
   -1    43                 errback(value).then(d.resolve, d.reject)
   82    44 
   83    -1         """
   -1    45     def then(self, callback, errback=None):
   84    46         _callback = wrap(callback, default=when)
   85    47         _errback = wrap(errback, default=reject)
   86    48 
@@ -89,50 +51,48 @@ class Promise(object):
   89    51         elif self._status == REJECTED:
   90    52             return _errback(self._value)
   91    53         else:  # OPEN
   92    -1             d = Deferred()
   93    -1             self._children.append((d, _callback, _errback))
   94    -1             return d.promise
   -1    54             promise = Promise()
   -1    55             self._children.append((promise, _callback, _errback))
   -1    56             return promise
   95    57 
   96    -1     def _raise(self):
   97    -1         if self._status == REJECTED and isinstance(self._value, Exception):
   98    -1             raise self._value
   -1    58     def catch(self, errback):
   -1    59         return self.then(None, errback)
   99    60 
  100    61 
  101    62 def when(value=None):
  102    -1     """Wrap value in a promise if it is not already one."""
  103    63     if isinstance(value, Promise):
  104    64         return value
  105    65     else:
  106    -1         d = Deferred()
  107    -1         d.resolve(value)
  108    -1         return d.promise
   -1    66         promise = Promise()
   -1    67         promise.resolve(value)
   -1    68         return promise
  109    69 
  110    70 
  111    71 def reject(value=None):
  112    -1     """Shortcut for creating a rejecting promise."""
  113    -1     d = Deferred()
  114    -1     d.reject(value)
  115    -1     return d.promise
   -1    72     if isinstance(value, Promise):
   -1    73         return value
   -1    74     else:
   -1    75         promise = Promise()
   -1    76         promise.reject(value)
   -1    77         return promise
  116    78 
  117    79 
  118    -1 def wrap(fun, default=None):
  119    -1     """Wrap a function so that it always returns a promise."""
  120    -1     def _fun(*args, **kwargs):
   -1    80 def wrap(fn, default=None):
   -1    81     def wrapped(*args, **kwargs):
  121    82         try:
  122    -1             result = fun(*args, **kwargs)
   -1    83             value = fn(*args, **kwargs)
  123    84         except Exception as err:
  124    85             return reject(err)
  125    -1         return when(result)
   -1    86         return when(value)
  126    87 
  127    -1     if fun is None:
   -1    88     if fn is None:
  128    89         return default
  129    90     else:
  130    -1         return _fun
   -1    91         return wrapped
  131    92 
  132    93 
  133    -1 def all(*promises):
  134    -1     """Convert a list of promises to a promise of a list."""
  135    -1     d = Deferred()
   -1    94 def all(promises):
   -1    95     result = Promise()
  136    96     data = {
  137    97         'count': len(promises),
  138    98         'results': [None] * len(promises),
@@ -144,18 +104,11 @@ def all(*promises):
  144   104             data['count'] -= 1
  145   105 
  146   106             if data['count'] == 0:
  147    -1                 d.resolve(data['results'])
   -1   107                 result.resolve(data['results'])
   -1   108 
  148   109         return success
  149   110 
  150   111     for i, promise in enumerate(promises):
  151    -1         promise.then(success_factory(i), d.reject)
  152    -1 
  153    -1     return d.promise
  154    -1 
  155    -1 
  156    -1 def fromTwisted(twistedDeferred):
  157    -1     """Convert a twisted deferred to a promise."""
   -1   112         promise.then(success_factory(i), result.reject)
  158   113 
  159    -1     d = Deferred()
  160    -1     twistedDeferred.addCallbacks(d.resolve, d.reject)
  161    -1     return d.promise
   -1   114     return result

diff --git a/laneya/protocol.py b/laneya/protocol.py

@@ -67,7 +67,7 @@ import logging
   67    67 
   68    68 import trollius as asyncio
   69    69 
   70    -1 from . import deferred as q
   -1    70 from . import promise as q
   71    71 from . import actions
   72    72 
   73    73 logger = logging.getLogger('laneya')
@@ -273,7 +273,7 @@ class ClientProtocol(BaseProtocol):
  273   273     def __init__(self, factory):
  274   274         super(ClientProtocol, self).__init__()
  275   275         self.factory = factory
  276    -1         self._response_deferreds = {}
   -1   276         self._response_promises = {}
  277   277 
  278   278     def connection_made(self, transport):
  279   279         super(ClientProtocol, self).connection_made(transport)
@@ -287,16 +287,16 @@ class ClientProtocol(BaseProtocol):
  287   287         if message['type'] == 'response':
  288   288             self.validate_message(message, ['data', 'key', 'status', 'type'])
  289   289             key = message['key']
  290    -1             if key in self._response_deferreds:
   -1   290             if key in self._response_promises:
  291   291                 response = {
  292   292                     'status': message['status'],
  293   293                     'data': message['data'],
  294   294                 }
  295    -1                 d = self._response_deferreds.pop(key)
   -1   295                 promise = self._response_promises.pop(key)
  296   296                 if message['status'] == 'success':
  297    -1                     d.resolve(response)
   -1   297                     promise.resolve(response)
  298   298                 else:
  299    -1                     d.reject(response)
   -1   299                     promise.reject(response)
  300   300 
  301   301         elif message['type'] == 'update':
  302   302             self.validate_message(message, ['action', 'data', 'type'])
@@ -309,10 +309,10 @@ class ClientProtocol(BaseProtocol):
  309   309     def update_received(self, action, **kwargs):
  310   310         self.factory.update_received(action, **kwargs)
  311   311 
  312    -1     def _timeout(self, d, key):
   -1   312     def _timeout(self, promise, key):
  313   313         try:
  314    -1             d.reject('timeout', silent=True)
  315    -1             del self._response_deferreds[key]
   -1   314             promise.reject('timeout')
   -1   315             del self._response_promises[key]
  316   316         except KeyError:
  317   317             pass
  318   318 
@@ -326,10 +326,10 @@ class ClientProtocol(BaseProtocol):
  326   326         }
  327   327         self.send_json(data)
  328   328 
  329    -1         d = q.Deferred()
  330    -1         self._response_deferreds[data['key']] = d
  331    -1         self.factory.loop.call_later(2, self._timeout, d, data['key'])
  332    -1         return d.promise
   -1   329         promise = q.Promise()
   -1   330         self._response_promises[data['key']] = promise
   -1   331         self.factory.loop.call_later(2, self._timeout, promise, data['key'])
   -1   332         return promise
  333   333 
  334   334 
  335   335 class ClientProtocolFactory(object):