78 lines
2.2 KiB
Python
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)
|