mirror of git://git.psyced.org/git/pypsyc
101 lines
3.7 KiB
Python
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)
|