""" 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)