pypsyc/mjacob2/pypsyc/server/multicast.py

101 lines
3.7 KiB
Python

"""
pypsyc.server.multicast
~~~~~~~~~~~~~~~~~~
:copyright: 2010 by Manuel Jacob
:license: MIT
"""
from collections import defaultdict
from pypsyc.core.mmp import Header
from pypsyc.core.psyc import PSYCPacket
from pypsyc.protocol import ContextSlave as ContextSlaveProtocol
class ContextMaster(object):
def __init__(self, entity):
self.state = {}
self.list_state = defaultdict(list)
self.entity = entity
if hasattr(entity.server.routing.mrouting_table, '__setitem__'):
entity.server.routing.mrouting_table[entity.uni] = set()
def add_member(self, uni):
if not uni.is_descendant_of(self.entity._root.uni):
routing = self.entity.server.routing
circuit = routing.srouting_table[uni.into_parts()[0]]
routing.mrouting_table[self.entity.uni].add(circuit)
state = self.state.copy()
state.update((k, '|'.join(v)) for k, v in self.list_state.iteritems())
return state
def remove_member(self, uni):
if not uni.is_descendant_of(self.entity._root.uni):
routing = self.entity.server.routing
circuit = routing.srouting_table[uni.into_parts()[0]]
routing.mrouting_table[self.entity.uni].remove(circuit)
def state_set(self, **kwds):
self.state.update(kwds)
self.entity.castmsg(PSYCPacket({'=': kwds}))
def state_add(self, **kwds):
for key, value in kwds.iteritems():
self.list_state[key].append(value)
self.entity.castmsg(PSYCPacket({'+': kwds}))
def state_remove(self, **kwds):
for key, value in kwds.iteritems():
idx = self.list_state[key].index(value)
for i, j in self.list_state.items():
if i.startswith(key):
del j[idx]
if not j:
del self.list_state[i]
self.entity.castmsg(PSYCPacket({'-': kwds}))
class ContextSlave(object):
def __init__(self, person):
self.protocol = ContextSlaveProtocol(person)
self.person = person
self.subscribed_contexts = set()
def enter(self, context, resource=None):
if context not in self.subscribed_contexts:
state = self.protocol.enter(context)
self.subscribed_contexts.add(context)
else:
state = None # TODO: get state from context master
entity = self.person.entity
table = entity.server.routing.mrouting_table.setdefault(context, set())
resources = ([entity.children[resource.into_parts()[-1]]] if resource
else entity.children.values())
table.update(resource.circuit for resource in resources)
if state:
header = Header({'_context': context})
content = list(PSYCPacket({'=': state}).render())
for resource in resources:
resource.circuit.send(header, content)
def leave(self, context, resource=None):
if context not in self.subscribed_contexts:
return
entity = self.person.entity
table = entity.server.routing.mrouting_table[context]
circuits = (r.circuit for r in entity.children.itervalues())
if resource:
table.remove(entity.children[resource.into_parts()[-1]].circuit)
if table.intersection(circuits): return
else:
table.difference_update(circuits)
self.protocol.leave(context)
self.subscribed_contexts.remove(context)
if not (table or entity._root.uni.is_ancestor_of(context)):
del entity.server.routing.mrouting_table[context]
def leave_all(self):
for i in list(self.subscribed_contexts):
self.leave(i)