taijitu/state_management.py

78 lines
2.2 KiB
Python

from abots.helpers import generator, infinitedict
from gevent.lock import BoundedSemaphore
from collections import namedtuple
class AtomicDict(object):
def __init__(self, *args, **kwargs):
self._dict = dict()
self._lock = BoundedSemaphore()
def __enter__(self):
self._lock.acquire()
return self._dict
def __exit__(self, _type, value, traceback):
self._lock.release()
def get_state(meta):
state = infinitedict()
with meta as m:
state = m.get("state")
assert state is not None, "'state' is missing"
return state.copy()
def unsubscribe(meta, listener):
with meta as m:
listeners = m.get("listeners")
assert listener in listeners, f"'{listener}' missing from: {listeners}"
listeners.remove(listener)
def subscribe(meta, listener):
with meta as m:
listeners = m.get("listeners")
assert listeners is not None, "'listeners' is missing"
listeners.append(listener)
return lambda: unsubscribe(meta, listener)
@generator
def dispatch(meta):
action = (yield)
with meta as m:
is_dispatching = m.get("is_dispatching")
assert is_dispatching is not None, "'is_dispatching' is missing"
if is_dispatching:
raise Exception("Reducers cannot dispatch actions")
try:
with meta as m:
m["is_dispatching"] = True
reducer = m.get("reducer")
assert reducer is not None, "'reducer' is missing"
m["state"] = reducer(state, action)
finally:
with meta as m:
m["is_dispatching"] = False
with meta as m:
listeners = m.get("listeners")
assert listeners is not None, "'listeners' is missing"
for listener in listeners[:]:
listener()
def manager(reducer, initial_state=infinitedict()):
meta = AtomicDict()
with meta as m:
m["listeners"] = list()
m["is_dispatching"] = False
m["reducer"] = reducer
m["state"] = initial_state
state = lambda: get_state(meta)
return state, dispatch(meta)
Action = namedtuple("Action", ["type", "payload"])
#meta, actions = manager(reducer)