def network_thread(self, ctx, pipe): print("Network thread started..") n = Pyre(self.name) n.join("Car2X") n.start() node_socket = n.socket() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(node_socket, zmq.POLLIN) while not self.stopped: items = dict(poller.poll(1000)) if pipe in items and items[pipe] == zmq.POLLIN: # handle outgoing messages message = pipe.recv() n.shouts("Car2X", message.decode('utf-8')) elif node_socket in items: cmds = n.recv() msg_type = cmds.pop(0) msg_uuid = cmds.pop(0) msg_name = cmds.pop(0) if msg_type == "JOIN": print("{} joined!".format(msg_name)) elif msg_type == "EXIT": print("{} left!".format(msg_name)) elif msg_type == "SHOUT": # handling incoming information msg_channel = cmds.pop(0) msg_str = cmds.pop(0) self.process_data(msg_str) n.stop()
def chat_task(ctx, pipe, ncmds): n = Pyre(ctx=ctx) n.join("CHAT") n.start() # wait for someone else to join the chat while not n.peer_groups(): pass pipe.send('ready'.encode('utf-8')) cmds = 0 t0 = time.time() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.inbox, zmq.POLLIN) while (True): items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break n.shout("CHAT", message) if n.inbox in items and items[n.inbox] == zmq.POLLIN: n.recv() cmds += 1 if cmds == ncmds: msg = 'Got %s msgs in %0.2f sec' % (cmds, time.time() - t0) pipe.send(msg.encode('utf-8')) n.stop()
def chat_task(ctx, pipe): n = Pyre(ctx) n.join("CHAT") n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.inbox, zmq.POLLIN) while(True): items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break print("CHAT_TASK: %s" % message) n.shout("CHAT", message) if n.inbox in items and items[n.inbox] == zmq.POLLIN: cmds = n.recv() type = cmds.pop(0) print("NODE_MSG TYPE: %s" % type) print("NODE_MSG PEER: %s" % uuid.UUID(bytes=cmds.pop(0))) print("NODE_MSG NAME: %s" % cmds.pop(0)) if type.decode('utf-8') == "SHOUT": print("NODE_MSG GROUP: %s" % cmds.pop(0)) print("NODE_MSG CONT: %s" % cmds) n.stop()
def chat_task(ctx, pipe, ncmds): n = Pyre(ctx) n.join("CHAT") n.start() # wait for someone else to join the chat while not n.get_peer_groups(): pass pipe.send('ready'.encode('utf-8')) cmds = 0 t0 = time.time() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.inbox, zmq.POLLIN) while(True): items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break n.shout("CHAT", message) if n.inbox in items and items[n.inbox] == zmq.POLLIN: n.recv() cmds += 1 if cmds == ncmds: msg = 'Got %s msgs in %0.2f sec' % (cmds, time.time() - t0) pipe.send(msg.encode('utf-8')) n.stop()
def run_time_sync_master(group): pts_group = group + '-time_sync-v1' # the time source in the example is python time.time you can change this. # replace with an implementation that give your custom time in floating sec. clock_service = Clock_Sync_Master(time) # This example is a clock service only, not a clock follower. # Therefore the rank is designed to always trump all others. rank = 1000 discovery = Pyre('pupil-helper-service') discovery.join(pts_group) discovery.start() logger.info('Joining "{}" group with rank {}'.format(pts_group, rank)) def announce_clock_service_info(): discovery.shout(pts_group, [repr(rank).encode(), repr(clock_service.port).encode()]) try: for event in discovery.events(): if event.type == 'JOIN' and event.group == pts_group: logger.info('"{}" joined "{}" group. Announcing service.'.format(event.peer_name, pts_group)) announce_clock_service_info() except KeyboardInterrupt: pass finally: logger.info('Leaving "{}" group'.format(pts_group)) discovery.leave(pts_group) discovery.stop() clock_service.stop()
class Network(): def __init__(self): self.node = Pyre("GAME_NODE") self.node.set_header("HELLO", "ABC") self.node.start() self.node.join("world:position") self.node.join("world:combat") self.poller = zmq.Poller() self.poller.register(self.node.socket(), zmq.POLLIN) def poll(self): return dict(self.poller.poll(0)) def peers(self): return self.node.peers() def stop(self): self.node.stop() def get_events(self): changes = self.poll() if self.node.socket() in changes and changes[ self.node.socket()] == zmq.POLLIN: events = self.node.recent_events() return events
class Client(object): def __exit__(self, exc_type, exc_val, exc_tb): self.engine.stop() def __init__(self, channel=ZYRE_CHANNEL, *args, **kvargs): self.logger = logging.getLogger('pyre') self.channel = channel self.engine = Pyre(self.channel) self.id = self.engine.uuid() def start(self, ctx, pipe): self.logger.info('joining channel') self.engine.join(self.channel) self.logger.info('starting engine...') self.engine.start() self.logger.info('id is: {}'.format(self.id)) poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(self.engine.socket(), zmq.POLLIN) while True: items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break self.logger.info("CHAT_TASK: %s" % message) self.engine.shouts(self.channel, message.decode('utf-8')) else: cmds = self.engine.recv() self.logger.info('HMMM {}'.format(cmds)) msg_type = cmds.pop(0) self.logger.info("NODE_MSG TYPE: %s" % msg_type) self.logger.info("NODE_MSG PEER: %s" % uuid.UUID(bytes=cmds.pop(0))) self.logger.info("NODE_MSG NAME: %s" % cmds.pop(0)) if msg_type.decode('utf-8') == "SHOUT": self.logger.info("NODE_MSG GROUP: %s" % cmds.pop(0)) elif msg_type.decode('utf-8') == "ENTER": headers = json.loads(cmds.pop(0).decode('utf-8')) self.logger.info("NODE_MSG HEADERS: %s" % headers) for key in headers: self.logger.info("key = {0}, value = {1}".format( key, headers[key])) self.logger.info("NODE_MSG CONT: %s" % cmds) self.engine.stop()
class Client(object): def __exit__(self, exc_type, exc_val, exc_tb): self.engine.stop() def __init__(self, channel=ZYRE_CHANNEL, *args, **kvargs): self.logger = logging.getLogger('pyre') self.channel = channel self.engine = Pyre(self.channel) self.id = self.engine.uuid() def start(self, ctx, pipe): self.logger.info('joining channel') self.engine.join(self.channel) self.logger.info('starting engine...') self.engine.start() self.logger.info('id is: {}'.format(self.id)) poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(self.engine.socket(), zmq.POLLIN) while True: items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break self.logger.info("CHAT_TASK: %s" % message) self.engine.shouts(self.channel, message.decode('utf-8')) else: cmds = self.engine.recv() self.logger.info('HMMM {}'.format(cmds)) msg_type = cmds.pop(0) self.logger.info("NODE_MSG TYPE: %s" % msg_type) self.logger.info("NODE_MSG PEER: %s" % uuid.UUID(bytes=cmds.pop(0))) self.logger.info("NODE_MSG NAME: %s" % cmds.pop(0)) if msg_type.decode('utf-8') == "SHOUT": self.logger.info("NODE_MSG GROUP: %s" % cmds.pop(0)) elif msg_type.decode('utf-8') == "ENTER": headers = json.loads(cmds.pop(0).decode('utf-8')) self.logger.info("NODE_MSG HEADERS: %s" % headers) for key in headers: self.logger.info("key = {0}, value = {1}".format(key, headers[key])) self.logger.info("NODE_MSG CONT: %s" % cmds) self.engine.stop()
def setup_group_member(): group_member = Pyre(self.name) # set headers for header in self.default_headers: group_member.set_header(*header) # join active group group_member.join(self.active_group) # start group_member group_member.start() return group_member
def network_thread(self, ctx, pipe): print("Network thread started..") n = Pyre(self.name) n.join("Car2X") n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.inbox, zmq.POLLIN) # wait for others while not n.peer_groups(): time.sleep(0.0001) pass pipe.send('$$ready'.encode('utf-8')) while not self.stopped: items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: # handle outgoing messages try: message = pipe.recv() if message.decode('utf-8') == "$$STOP": break n.shouts("Car2X", message.decode('utf-8')) except zmq.error.Again: print("ERROR! Again #1") if n.inbox in items and items[n.inbox] == zmq.POLLIN: try: cmds = n.recv() msg_type = cmds.pop(0) msg_uuid = cmds.pop(0) msg_name = cmds.pop(0) if msg_type == "JOIN": print("{} joined!".format(msg_name)) # ADD CAR IF NOT CONTROL if msg_name[0:1] != "$": self.window.hosts.append(msg_name) elif msg_type == "EXIT": print("{} left!".format(msg_name)) # REMOVE CAR if msg_name in self.window.hosts: self.window.hosts.remove(msg_name) elif msg_type == "SHOUT": # handling incoming information msg_channel = cmds.pop(0) msg_str = cmds.pop(0) self.process_data(msg_str, msg_name) except zmq.error.Again: print("ERROR! Again #2") n.stop()
def discovery_task(self, ctx, pipe): self.log.debug("Pyre on iface : {}".format(self.iface)) n = Pyre(self.groupName, sel_iface=self.iface) n.set_header("DISCOVERY_Header1", "DISCOVERY_HEADER") n.join(self.groupName) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.inbox, zmq.POLLIN) while (True): items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break if n.inbox in items and items[n.inbox] == zmq.POLLIN: cmds = n.recv() self.log.debug("NODE_MSG CONT:{}".format(cmds)) msg_type = cmds.pop(0) peer_uuid_bytes = cmds.pop(0) peer_uuid = uuid.UUID(bytes=peer_uuid_bytes) self.log.debug("NODE_MSG TYPE: {}".format(msg_type)) self.log.debug("NODE_MSG PEER: {}".format(peer_uuid)) if msg_type.decode('utf-8') == "SHOUT": group_name = cmds.pop(0) self.log.debug("NODE_MSG GROUP: {}".format(group_name)) group_name_2 = cmds.pop(0) self.log.debug("NODE_MSG GROUP_2: {}".format(group_name_2)) discoveryMsg = cmds.pop(0) self.log.debug("Discovery Msg : {}".format(discoveryMsg)) controller = json.loads(discoveryMsg.decode('utf-8')) self.controller_dl = str(controller["downlink"]) self.controller_ul = str(controller["uplink"]) self.log.debug("Discovered Controller DL-{}, UL-{}".format( self.controller_dl, self.controller_ul)) self.send_event( events.BrokerDiscoveredEvent(self.controller_dl, self.controller_ul)) n.stop()
def _thread_loop(self,context,pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.socket(), zmq.POLLIN) front,back = zhelper.zcreate_pipe(context) poller.register(back, zmq.POLLIN) def wake_up(): #on app close this timer calls a closed socket. We simply catch it here. try: front.send('wake_up') except Exception as e: logger.debug('Orphaned timer thread raised error: %s'%e) if self._time_grandmaster: t = Timer(0.1, wake_up) else: t = Timer(self.time_sync_announce_interval, wake_up) t.daemon = True t.start() while(True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll()) except zmq.ZMQError: logger.warning('Socket fail.') continue if back in items and items[back] == zmq.POLLIN: self._handle_wake_up(back,n,wake_up) if pipe in items and items[pipe] == zmq.POLLIN: if self._handle_internal(pipe,n): break if n.socket() in items and items[n.socket()] == zmq.POLLIN: self._handle_network(n) else: pass logger.debug('_thread_loop closing.') self.thread_pipe = None n.stop()
def gaze_exchange_task(self, ctx, pipe): """ Task for exchanging messages Args: ctx(zmq.Context): the zmq context pipe(zmq.PAIR pipe): the pipe for exchanging messages Returns: (zmq.PAIR pipe) the pipe """ n = Pyre("GAZE_EXCHANGE") self.publisher_id = n.uuid() n.join(GROUP_GAZE_EXCHANGE) n.start() poller = zmq.Poller() # noinspection PyUnresolvedReferences poller.register(pipe, zmq.POLLIN) # noinspection PyUnresolvedReferences poller.register(n.socket(), zmq.POLLIN) while not self.stopped: items = dict(poller.poll()) print(n.socket(), items) # noinspection PyUnresolvedReferences if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit message = message.decode('utf-8') if message == STOP_MESSAGE: break print("GAZE_EXCHANGE_TASK: {}".format(message)) self.save_gaze_from_message(message) n.shouts(GROUP_GAZE_EXCHANGE, message) else: cmds = n.recv() msg_type = cmds.pop(0) print("NODE_MSG TYPE: %s" % msg_type) print("NODE_MSG PEER: %s" % uuid.UUID(bytes=cmds.pop(0))) print("NODE_MSG NAME: %s" % cmds.pop(0)) if msg_type.decode('utf-8') == "SHOUT": print("NODE_MSG GROUP: %s" % cmds.pop(0)) message = cmds.pop(0).decode("utf-8") self.save_gaze_from_message(message) elif msg_type.decode('utf-8') == "ENTER": headers = json.loads(cmds.pop(0).decode('utf-8')) print("NODE_MSG HEADERS: %s" % headers) for key in headers: print("key = {0}, value = {1}".format( key, headers[key])) print("NODE_MSG CONT: %s" % cmds) n.stop()
def discovery_task(self, ctx, pipe): self.log.debug("Pyre on iface : {}".format(self.iface)) n = Pyre(self.groupName, sel_iface=self.iface) n.set_header("DISCOVERY_Header1","DISCOVERY_HEADER") n.join(self.groupName) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.inbox, zmq.POLLIN) while(True): items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break if n.inbox in items and items[n.inbox] == zmq.POLLIN: cmds = n.recv() #self.log.error("NODE_MSG CONT:{}".format(cmds)) msg_type = cmds.pop(0) peer_uuid_bytes = cmds.pop(0) peer_uuid = uuid.UUID(bytes=peer_uuid_bytes) #self.log.debug("NODE_MSG TYPE: {}".format(msg_type)) #self.log.debug("NODE_MSG PEER: {}".format(peer_uuid)) if msg_type.decode('utf-8') == "SHOUT": group_name = cmds.pop(0) #self.log.debug("NODE_MSG GROUP: {}".format(group_name)) group_name_2 = cmds.pop(0) #self.log.debug("NODE_MSG GROUP_2: {}".format(group_name_2)) discoveryMsg = cmds.pop(0) #self.log.debug("Discovery Msg : {}".format(discoveryMsg)) controller = json.loads(discoveryMsg.decode('utf-8')) self.controller_dl = str(controller["downlink"]) self.controller_ul = str(controller["uplink"]) self.log.info("Discovered Controller DL-{}, UL-{}".format(self.controller_dl, self.controller_ul)) n.stop()
def indicators_create(self, data, **kwargs): if isinstance(data, dict): data = Indicator(**data) if isinstance(data, Indicator): data = [data] n = Pyre() n.join(CHAN) n.start() sleep(1) for i in data: n.shouts(CHAN, str(i)) n.stop()
def discovery_task(self, ctx, pipe): self.log.debug("Pyre on iface : {}".format(self.iface)) n = Pyre(self.groupName, sel_iface=self.iface) n.set_header("DISCOVERY_Header1","DISCOVERY_HEADER") n.join(self.groupName) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) while(True): items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break n.shout(self.groupName, message) n.stop()
def discovery_task(self, ctx, pipe): self.log.debug("Pyre on iface : {}".format(self.iface)) n = Pyre(self.groupName, sel_iface=self.iface) n.set_header("DISCOVERY_Header1", "DISCOVERY_HEADER") n.join(self.groupName) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) while (True): items = dict(poller.poll()) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "$$STOP": break n.shout(self.groupName, message) n.stop()
def run_time_sync_master(group): pts_group = group + '-time_sync-v1' # the time source in the example is python time.time you can change this. # replace with an implementation that give your custom time in floating sec. clock_service = Clock_Sync_Master(time) # This example is a clock service only, not a clock follower. # Therefore the rank is designed to always trump all others. rank = 1000 discovery = Pyre('pupil-helper-service') discovery.join(pts_group) discovery.start() logger.info('Joining "{}" group with rank {}'.format(pts_group, rank)) def announce_clock_service_info(): discovery.shout( pts_group, [repr(rank).encode(), repr(clock_service.port).encode()]) try: for event in discovery.events(): if event.type == 'JOIN' and event.group == pts_group: logger.info( '"{}" joined "{}" group. Announcing service.'.format( event.peer_name, pts_group)) announce_clock_service_info() except KeyboardInterrupt: pass finally: logger.info('Leaving "{}" group'.format(pts_group)) discovery.leave(pts_group) discovery.stop() clock_service.stop()
class Time_Sync(Plugin): """Synchronize time across local network. Implements the Pupil Time Sync protocol. Acts as clock service and as follower if required. See `time_sync_spec.md` for details. """ icon_chr = chr(0xec15) icon_font = 'pupil_icons' def __init__(self, g_pool, node_name=None, sync_group_prefix='default', base_bias=1.): super().__init__(g_pool) self.sync_group_prefix = sync_group_prefix self.discovery = None self.leaderboard = [] self.has_been_master = 0. self.has_been_synced = 0. self.tie_breaker = random.random() self.base_bias = base_bias self.master_service = Clock_Sync_Master(self.g_pool.get_timestamp) self.follower_service = None # only set if there is a better server than us self.restart_discovery(node_name) @property def sync_group(self): return self.sync_group_prefix + '-time_sync-' + __protocol_version__ @sync_group.setter def sync_group(self, full_name): self.sync_group_prefix = full_name.rsplit('-time_sync-' + __protocol_version__, maxsplit=1)[0] def init_ui(self): self.add_menu() self.menu.label = 'Network Time Sync' help_str = "Synchonize time of Pupil Captures across the local network." self.menu.append(ui.Info_Text('Protocol version: ' + __protocol_version__)) self.menu.append(ui.Info_Text(help_str)) help_str = "All pupil nodes of one group share a Master clock." self.menu.append(ui.Info_Text(help_str)) self.menu.append(ui.Text_Input('node_name', self, label='Node Name', setter=self.restart_discovery)) self.menu.append(ui.Text_Input('sync_group_prefix', self, label='Sync Group', setter=self.change_sync_group)) def sync_status(): if self.follower_service: return str(self.follower_service) else: return 'Clock Master' self.menu.append(ui.Text_Input('sync status', getter=sync_status, setter=lambda _: _, label='Status')) def set_bias(bias): if bias < 0: bias = 0. self.base_bias = bias self.announce_clock_master_info() self.evaluate_leaderboard() help_str = "The clock service with the highest bias becomes clock master." self.menu.append(ui.Info_Text(help_str)) self.menu.append(ui.Text_Input('base_bias', self, label='Master Bias', setter=set_bias)) self.menu.append(ui.Text_Input('leaderboard', self, label='Master Nodes in Group')) def recent_events(self, events): should_announce = False for evt in self.discovery.recent_events(): if evt.type == 'SHOUT': try: self.update_leaderboard(evt.peer_uuid, evt.peer_name, float(evt.msg[0]), int(evt.msg[1])) except Exception as e: logger.debug('Garbage raised `{}` -- dropping.'.format(e)) self.evaluate_leaderboard() elif evt.type == 'JOIN' and evt.group == self.sync_group: should_announce = True elif (evt.type == 'LEAVE' and evt.group == self.sync_group) or evt.type == 'EXIT': self.remove_from_leaderboard(evt.peer_uuid) self.evaluate_leaderboard() if should_announce: self.announce_clock_master_info() if not self.has_been_synced and self.follower_service and self.follower_service.in_sync: self.has_been_synced = 1. self.announce_clock_master_info() self.evaluate_leaderboard() def update_leaderboard(self, uuid, name, rank, port): for cs in self.leaderboard: if cs.uuid == uuid: if (cs.rank != rank) or (cs.port != port): self.remove_from_leaderboard(cs.uuid) break else: # no changes. Just leave as is return # clock service was not encountered before or has changed adding it to leaderboard cs = Clock_Service(uuid, name, rank, port) heappush(self.leaderboard, cs) logger.debug('{} added'.format(cs)) def remove_from_leaderboard(self, uuid): for cs in self.leaderboard: if cs.uuid == uuid: self.leaderboard.remove(cs) logger.debug('{} removed'.format(cs)) break def evaluate_leaderboard(self): if not self.leaderboard: logger.debug("nobody on the leader board.") return current_leader = self.leaderboard[0] if self.discovery.uuid() != current_leader.uuid: # we are not the leader! leader_ep = self.discovery.peer_address(current_leader.uuid) leader_addr = urlparse(leader_ep).netloc.split(':')[0] if self.follower_service is None: # make new follower self.follower_service = Clock_Sync_Follower(leader_addr, port=current_leader.port, interval=10, time_fn=self.get_time, jump_fn=self.jump_time, slew_fn=self.slew_time) else: # update follower_service self.follower_service.host = leader_addr self.follower_service.port = current_leader.port return # we are the leader logger.debug("we are the leader") if self.follower_service is not None: self.follower_service.terminate() self.follower_service = None if not self.has_been_master: self.has_been_master = 1. logger.debug('Become clock master with rank {}'.format(self.rank)) self.announce_clock_master_info() def announce_clock_master_info(self): self.discovery.shout(self.sync_group, [repr(self.rank).encode(), repr(self.master_service.port).encode()]) self.update_leaderboard(self.discovery.uuid(), self.node_name, self.rank, self.master_service.port) @property def rank(self): return 4*self.base_bias + 2*self.has_been_master + self.has_been_synced + self.tie_breaker def get_time(self): return self.g_pool.get_timestamp() def slew_time(self, offset): self.g_pool.timebase.value += offset def jump_time(self, offset): ok_to_change = True for p in self.g_pool.plugins: if p.class_name == 'Recorder': if p.running: ok_to_change = False logger.error("Request to change timebase during recording ignored. Turn off recording first.") break if ok_to_change: self.slew_time(offset) logger.info("Pupil Sync has adjusted the clock by {}s".format(offset)) return True else: return False def restart_discovery(self, name): if self.discovery: if self.discovery.name() == name: return else: self.discovery.leave(self.sync_group) self.discovery.stop() self.leaderboard = [] self.node_name = name or gethostname() self.discovery = Pyre(self.node_name) # Either joining network for the first time or rejoining the same group. self.discovery.join(self.sync_group) self.discovery.start() self.announce_clock_master_info() def change_sync_group(self, new_group_prefix): if new_group_prefix != self.sync_group_prefix: self.discovery.leave(self.sync_group) self.leaderboard = [] if self.follower_service: self.follower_service.terminate() self.follower = None self.sync_group_prefix = new_group_prefix self.discovery.join(self.sync_group) self.announce_clock_master_info() def deinit_ui(self): self.remove_menu() def get_init_dict(self): return {'node_name': self.node_name, 'sync_group_prefix': self.sync_group_prefix, 'base_bias': self.base_bias} def cleanup(self): self.discovery.leave(self.sync_group) self.discovery.stop() self.master_service.stop() if self.follower_service: self.follower_service.stop() self.master_service = None self.follower_service = None self.discovery = None
def chat_task(ctx, pipe): print("Game started") print("Name: %s" %NAME) connected_players = 1 network_players = 1 leave_counter = 0 #Set up node for the game n = Pyre("") n.set_header("header_name", NAME) #Join the group n.join(GROUPNAME) #Start broadcasting node n.start() # Set up poller poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) #Local pipe (contains commands/messages we send through terminal) poller.register(n.socket(), zmq.POLLIN) # A while loop constantly polls for new items = PULL system while True: #Wait for new message to be polled. This function blocks until there is a new message items = dict(poller.poll()) #This are messages from ourselves if pipe in items: message_pipe = pipe.recv() if message_pipe.decode('utf-8') == STOP_COMMAND: break #check if the message is a number elif message_pipe.decode('utf-8').isdigit() == True and yourturn == True: #variable to keep the loop going until a correct number is given status = True #check which symbol you got assigned if playerX == True: while status == True: number = int(message_pipe.decode('utf-8')) #check if the spot is free if board[number] != "X" and board[number] != "O": status = False yourturn = False print("New status board:") board[number] = "X" showboard() #check for a winning combination if checkall("X") == True: print("You win!") n.whisper(OPPONENT,str(number).encode('utf-8')) break #when there's no winning combination, it's the other player's turn else: print("Waiting for opponent's move...") #let your opponent know which number you chose n.whisper(OPPONENT,str(number).encode('utf-8')) else: print("Spot taken, try again") message_pipe = pipe.recv() else: while status == True: number = int(message_pipe.decode('utf-8')) if board[number] != "X" and board[number] != "O": status = False yourturn = False print("New status board:") board[number] = "O" showboard() if checkall("O") == True: print("You win!") n.whisper(OPPONENT,str(number).encode('utf-8')) break else: print("Waiting for opponent's move...") n.whisper(OPPONENT,str(number).encode('utf-8')) else: print("Spot taken, try again") message_pipe = pipe.recv() elif message_pipe.decode('utf-8').isdigit() == True and yourturn == False: print("It's not your turn, wait for your opponent's move") #if the message isn't a number, it is send as a message to your opponent else: print("Sending message to opponent: %s" %message_pipe.decode('utf-8')) n.whisper(OPPONENT,message_pipe) # Received messages from system or messages from other peers else: cmds = n.recv() #print(">>>>>>>RECEIVED MESSAGE: ", cmds) msg_type = cmds.pop(0) player_uuid = uuid.UUID(bytes=cmds.pop(0)) #OPPONENT = player_uuid #print("player uuid: ", player_uuid) msg_name = cmds.pop(0) if msg_type.decode('utf-8') == "ENTER": headers = json.loads(cmds.pop(0).decode('utf-8')) network_players += 1 if network_players == 2: print("--------------------------------------------------------------------------------") print("New player discovered in network") print("Name:", headers.get("header_name")) print("--------------------------------------------------------------------------------") elif msg_type.decode('utf-8') == "JOIN": connected_players += 1 #check if there's stil room for a player if connected_players > 2: leave = "No free spot left" n.whisper(player_uuid, leave.encode('utf-8')) elif connected_players == 2: print("--------------------------------------------------------------------------------") print("%s joined group" %headers.get("header_name"), cmds.pop(0).decode('utf-8')) print("--------------------------------------------------------------------------------") #if there are 2 players, you know your opponent: OPPONENT = player_uuid showboard() #randomly choose if you want to start assign = random.randint(0,1) if assign == 1: player_start = True n.whisper(OPPONENT, "$$Istart".encode('utf-8')) else: player_start = False n.whisper(OPPONENT, "$$Ustart".encode('utf-8')) elif msg_type.decode('utf-8') == "WHISPER": message_opponent = cmds.pop(0).decode('utf-8') if message_opponent == "No free spot left": leave_counter += 1 #if you get the message that you must leave from 2 other players, you are the third player if leave_counter == 2: print(message_opponent) break #if the random generators both got a compatible result, the game can start elif message_opponent == "$$Istart" and player_start == False: playerX = False yourturn = False print("You are symbol O") print("You opponent may start, please wait...") elif message_opponent == "$$Ustart" and player_start == True: playerX = True yourturn = True print("You are symbol X") print("You may start") print("Where do you want to place your X?") #when the results are incompatible: try again elif message_opponent == "$$Istart" and player_start == True: assign = random.randint(0,1) if assign == 1: player_start = True n.whisper(OPPONENT, "$$Istart".encode('utf-8')) else: player_start = False n.whisper(OPPONENT, "$$Ustart".encode('utf-8')) elif message_opponent == "$$Ustart" and player_start == False: assign = random.randint(0,1) if assign == 1: player_start = True n.whisper(OPPONENT, "$$Istart".encode('utf-8')) else: player_start = False n.whisper(OPPONENT, "$$Ustart".encode('utf-8')) #if you receive a number, this is your opponent's move elif message_opponent.isdigit() == True: yourturn = True print("--------------------------------------------------------------------------------") print("Number opponent: ",message_opponent) print("New status board:") #check for a winning combination based on which player you are if playerX == True: board[int(message_opponent)] = "O" showboard() if checkall('O') == True: print("You loose!") break #if your opponent didn't make a winning combination, it's your turn else: print("Your turn") print("Where do you want to place your X?") else: board[int(message_opponent)] = "X" showboard() if checkall('X') == True: print("You loose!") break else: print("Your turn") print("Where do you want to place your O?") #if you just received a message, print it else: print("Opponent says: ",message_opponent) elif msg_type.decode('utf-8') == "EXIT": if connected_players == 2: print("%s left network" %headers.get("header_name")) connected_players -= 1 print("Total connected players: ", connected_players) leave_counter -= 1 print("Game stopped") n.stop()
def thread_loop(self,context,pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) logger.debug(n.socket()) poller.register(n.socket(), zmq.POLLIN) while(True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll()) except zmq.ZMQError: logger.warning('Socket fail.') # print(n.socket(), items) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "EXIT_THREAD": break logger.debug("Emitting to '%s' to '%s' " %(message,self.group)) n.shouts(self.group, message) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uid,name,group,msg = cmds logger.debug("'%s' shouts '%s'."%(name,msg)) if start_rec in msg : session_name = msg.replace(start_rec,'') self.notify_all({'name':'rec_should_start','session_name':session_name,'network_propagate':False}) elif stop_rec in msg: self.notify_all({'name':'rec_should_stop','network_propagate':False}) elif sync_time in msg: offset = float(msg.replace(sync_time,'')) if self.ok_to_set_timebase(): self.adjust_timebase(offset) elif msg_type == "ENTER": uid,name,headers,ip = cmds elif msg_type == "JOIN": uid,name,group = cmds if group == self.group: self.group_members[uid] = name self.update_gui() elif msg_type == "EXIT": uid,name = cmds try: del self.group_members[uid] except KeyError: pass else: self.update_gui() elif msg_type == "LEAVE": uid,name,group = cmds elif msg_tpye == "WHISPER": pass logger.debug('thread_loop closing.') self.thread_pipe = None n.stop()
def thread_loop(self,context,pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.socket(), zmq.POLLIN) front,back = zhelper.zcreate_pipe(context) poller.register(back, zmq.POLLIN) def wake_up(): #on app close this timer calls a closed socket. We simply catch it here. try: front.send('wake_up') except Exception as e: logger.debug('Orphaned timer thread raised error: %s'%e) t = Timer(self.time_sync_announce_interval, wake_up) t.daemon = True t.start() while(True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll()) except zmq.ZMQError: logger.warning('Socket fail.') continue if back in items and items[back] == zmq.POLLIN: back.recv() #timeout events are used for pupil sync. #annouce masterhood every interval time: if isinstance(self.sync_node,Clock_Sync_Master): n.shouts(self.group, SYNC_TIME_MASTER_ANNOUNCE+"%s"%self.clock_master_worthiness()+msg_delimeter+'%s'%self.sync_node.port) # synced slave: see if we should become master if we dont hear annoncement within time. elif isinstance(self.sync_node,Clock_Sync_Follower) and not self.sync_node.offset_remains: if self.get_monotonic_time()-self.last_master_announce > self.time_sync_wait_interval_short: self.sync_node.terminate() self.sync_node = Clock_Sync_Master(time_fn=self.get_time) n.shouts(self.group, SYNC_TIME_MASTER_ANNOUNCE+"%s"%self.clock_master_worthiness()+msg_delimeter+'%s'%self.sync_node.port) # unsynced slave or none should wait longer but eventually take over elif self.get_monotonic_time()-self.last_master_announce > self.time_sync_wait_interval_long: if self.sync_node: self.sync_node.terminate() self.sync_node = Clock_Sync_Master(time_fn=self.get_time) n.shouts(self.group, SYNC_TIME_MASTER_ANNOUNCE+"%s"%self.clock_master_worthiness()+msg_delimeter+'%s'%self.sync_node.port) t = Timer(self.time_sync_announce_interval, wake_up) t.daemon = True t.start() if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == exit_thread: break else: logger.debug("Shout '%s' to '%s' " %(message,self.group)) n.shouts(self.group, message) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uuid,name,group,msg = cmds logger.debug("'%s' shouts '%s'."%(name,msg)) self.handle_msg(uuid,name,msg,n) elif msg_type == "WHISPER": uuid,name,msg = cmds logger.debug("'%s/' whispers '%s'."%(name,msg)) self.handle_msg_whisper(uuid,name,msg,n) elif msg_type == "JOIN": uuid,name,group = cmds if group == self.group: self.group_members[uuid] = name self.update_gui() elif msg_type == "EXIT": uuid,name = cmds try: del self.group_members[uuid] except KeyError: pass else: self.update_gui() # elif msg_type == "LEAVE": # uuid,name,group = cmds # elif msg_type == "ENTER": # uuid,name,headers,ip = cmds # logger.warning((uuid,'name',headers,ip)) else: pass logger.debug('thread_loop closing.') self.thread_pipe = None n.stop()
class Bridge(object): """docstring for Bridge""" def __init__(self, uvc_id): super(Bridge, self).__init__() self.data_seq = 0 self.note_seq = 0 # init capture self.cap = uvc.Capture(uvc_id) logger.info('Initialised uvc device {}'.format(self.cap.name)) # init pyre self.network = Pyre(socket.gethostname() + self.cap.name[-4:]) self.network.join(GROUP) self.network.start() logger.info('Bridging under "{}"'.format(self.network.name())) # init sensor sockets ctx = zmq.Context() generic_url = 'tcp://*:*' public_ep = self.network.endpoint() self.note, self.note_url = self.bind(ctx, zmq.PUB, generic_url, public_ep) self.data, self.data_url = self.bind(ctx, zmq.PUB, generic_url, public_ep, set_hwm=1) self.cmd, self.cmd_url = self.bind(ctx, zmq.PULL, generic_url, public_ep) def loop(self): logger.info('Entering bridging loop...') self.network.shout(GROUP, self.sensor_attach_json().encode()) try: while True: self.poll_network() self.poll_cmd_socket() self.publish_frame() except KeyboardInterrupt: pass except Exception: import traceback traceback.print_exc() finally: self.network.shout( GROUP, json.dumps({ 'subject': 'detach', 'sensor_uuid': self.network.uuid().hex }).encode()) logger.info('Leaving bridging loop...') def publish_frame(self): frame = self.cap.get_frame_robust() now = time.time() index = self.data_seq self.data_seq += 1 self.data_seq %= sequence_limit jpeg_buffer = frame.jpeg_buffer m = hashlib.md5(jpeg_buffer) lower_end = int(m.hexdigest(), 16) % 0x100000000 meta_data = struct.pack('<LLLLdLL', 0x10, frame.width, frame.height, index, now, jpeg_buffer.size, lower_end) self.data.send_multipart( [self.network.uuid().hex.encode(), meta_data, jpeg_buffer]) def poll_network(self): for event in self.network.recent_events(): if event.type == 'JOIN' and event.group == GROUP: self.network.whisper(event.peer_uuid, self.sensor_attach_json().encode()) def poll_cmd_socket(self): while has_data(self.cmd): sensor, cmd_str = self.cmd.recv_multipart() try: cmd = json.loads(cmd_str.decode()) except Exception as e: logger.debug( 'Could not parse received cmd: {}'.format(cmd_str)) else: logger.debug('Received cmd: {}'.format(cmd)) if cmd.get('action') == 'refresh_controls': self.publish_controls() elif cmd.get('action') == 'set_control_value': val = cmd.get('value', 0) if cmd.get('control_id') == 'CAM_RATE': self.cap.frame_rate = self.cap.frame_rates[val] elif cmd.get('control_id') == 'CAM_RES': self.cap.frame_size = self.cap.frame_sizes[val] self.publish_controls() def __del__(self): self.note.close() self.data.close() self.cmd.close() self.network.stop() def publish_controls(self): self.note.send_multipart([ self.network.uuid().hex.encode(), self.frame_size_control_json().encode() ]) self.note.send_multipart([ self.network.uuid().hex.encode(), self.frame_rate_control_json().encode() ]) def sensor_attach_json(self): sensor = { "subject": "attach", "sensor_name": self.cap.name, "sensor_uuid": self.network.uuid().hex, "sensor_type": 'video', "notify_endpoint": self.note_url, "command_endpoint": self.cmd_url, "data_endpoint": self.data_url } return json.dumps(sensor) def frame_size_control_json(self): index = self.note_seq self.note_seq += 1 self.note_seq %= sequence_limit curr_fs = self.cap.frame_sizes.index(self.cap.frame_size) return json.dumps({ "subject": "update", "control_id": "CAM_RES", "seq": index, "changes": { "value": curr_fs, "dtype": 'intmapping', "min": None, "max": None, "res": None, "def": 0, "caption": 'Resolution', "readonly": False, "map": [{ 'value': idx, 'caption': '{:d}x{:d}'.format(*fs) } for idx, fs in enumerate(self.cap.frame_sizes)] } }) def frame_rate_control_json(self): index = self.note_seq self.note_seq += 1 self.note_seq %= sequence_limit curr_fr = self.cap.frame_rates.index(self.cap.frame_rate) return json.dumps({ "subject": "update", "control_id": "CAM_RATE", "seq": index, "changes": { "value": curr_fr, "dtype": 'intmapping', "min": None, "max": None, "res": None, "def": 0, "caption": 'Frame Rate', "readonly": False, "map": [{ 'value': idx, 'caption': '{:.1f} Hz'.format(fr) } for idx, fr in enumerate(self.cap.frame_rates)] } }) def bind(self, ctx, sock_type, url, public_ep, set_hwm=None): sock = ctx.socket(sock_type) if set_hwm: sock.set_hwm(set_hwm) sock.bind(url) ep = sock.last_endpoint.decode() port = ep.split(':')[-1] public_ep.split(':')[-1] public_addr = public_ep.split(':')[:-1] return sock, ':'.join(public_addr + [port])
class Network(): def __init__(self): self.node = Pyre("GAME_NODE") self.node.set_header("AUTHORITY", "FALSE") self.node.set_header("NAME", "") self.node.start() self.node.join("world:position") self.node.join("world:combat") self.node.join("ctf:teams") self.node.join("ctf:dropflag") self.node.join("ctf:gotflag") self.node.join("players:whois") self.node.join("player:name") self.node.join("ctf:scores") self.node.join("ctf:status") self.poller = zmq.Poller() self.poller.register(self.node.socket(), zmq.POLLIN) def poll(self): return dict(self.poller.poll(0)) def peers(self): return self.node.peers() def stop(self): self.node.stop() def get_events(self): changes = self.poll() if self.node.socket() in changes and changes[self.node.socket()] == zmq.POLLIN: events = self.node.recent_events() return events
class Bridge(object): """docstring for Bridge""" def __init__(self, uvc_id): super(Bridge, self).__init__() self.data_seq = 0 self.note_seq = 0 # init capture self.cap = uvc.Capture(uvc_id) logger.info('Initialised uvc device {}'.format(self.cap.name)) # init pyre self.network = Pyre(socket.gethostname()+self.cap.name[-4:]) self.network.join(GROUP) self.network.start() logger.info('Bridging under "{}"'.format(self.network.name())) # init sensor sockets ctx = zmq.Context() generic_url = 'tcp://*:*' public_ep = self.network.endpoint() self.note, self.note_url = self.bind(ctx, zmq.PUB, generic_url, public_ep) self.data, self.data_url = self.bind(ctx, zmq.PUB, generic_url, public_ep, set_hwm=1) self.cmd, self.cmd_url = self.bind(ctx, zmq.PULL, generic_url, public_ep) def loop(self): logger.info('Entering bridging loop...') self.network.shout(GROUP, self.sensor_attach_json().encode()) try: while True: self.poll_network() self.poll_cmd_socket() self.publish_frame() except KeyboardInterrupt: pass except Exception: import traceback traceback.print_exc() finally: self.network.shout(GROUP, json.dumps({ 'subject': 'detach', 'sensor_uuid': self.network.uuid().hex }).encode()) logger.info('Leaving bridging loop...') def publish_frame(self): frame = self.cap.get_frame_robust() now = time.time() index = self.data_seq self.data_seq += 1 self.data_seq %= sequence_limit jpeg_buffer = frame.jpeg_buffer m = hashlib.md5(jpeg_buffer) lower_end = int(m.hexdigest(), 16) % 0x100000000 meta_data = struct.pack('<LLLLdLL', 0x10, frame.width, frame.height, index, now, jpeg_buffer.size, lower_end) self.data.send_multipart([self.network.uuid().hex.encode(), meta_data, jpeg_buffer]) def poll_network(self): for event in self.network.recent_events(): if event.type == 'JOIN' and event.group == GROUP: self.network.whisper(event.peer_uuid, self.sensor_attach_json().encode()) def poll_cmd_socket(self): while has_data(self.cmd): sensor, cmd_str = self.cmd.recv_multipart() try: cmd = json.loads(cmd_str.decode()) except Exception as e: logger.debug('Could not parse received cmd: {}'.format(cmd_str)) else: logger.debug('Received cmd: {}'.format(cmd)) if cmd.get('action') == 'refresh_controls': self.publish_controls() elif cmd.get('action') == 'set_control_value': val = cmd.get('value', 0) if cmd.get('control_id') == 'CAM_RATE': self.cap.frame_rate = self.cap.frame_rates[val] elif cmd.get('control_id') == 'CAM_RES': self.cap.frame_size = self.cap.frame_sizes[val] self.publish_controls() def __del__(self): self.note.close() self.data.close() self.cmd.close() self.network.stop() def publish_controls(self): self.note.send_multipart([ self.network.uuid().hex.encode(), self.frame_size_control_json().encode()]) self.note.send_multipart([ self.network.uuid().hex.encode(), self.frame_rate_control_json().encode()]) def sensor_attach_json(self): sensor = { "subject": "attach", "sensor_name": self.cap.name, "sensor_uuid": self.network.uuid().hex, "sensor_type": 'video', "notify_endpoint": self.note_url, "command_endpoint": self.cmd_url, "data_endpoint": self.data_url } return json.dumps(sensor) def frame_size_control_json(self): index = self.note_seq self.note_seq += 1 self.note_seq %= sequence_limit curr_fs = self.cap.frame_sizes.index(self.cap.frame_size) return json.dumps({ "subject": "update", "control_id": "CAM_RES", "seq": index, "changes": { "value": curr_fs, "dtype": 'intmapping', "min": None, "max": None, "res": None, "def": 0, "caption": 'Resolution', "readonly": False, "map": [{ 'value': idx, 'caption': '{:d}x{:d}'.format(*fs) } for idx, fs in enumerate(self.cap.frame_sizes)] } }) def frame_rate_control_json(self): index = self.note_seq self.note_seq += 1 self.note_seq %= sequence_limit curr_fr = self.cap.frame_rates.index(self.cap.frame_rate) return json.dumps({ "subject": "update", "control_id": "CAM_RATE", "seq": index, "changes": { "value": curr_fr, "dtype": 'intmapping', "min": None, "max": None, "res": None, "def": 0, "caption": 'Frame Rate', "readonly": False, "map": [{ 'value': idx, 'caption': '{:.1f} Hz'.format(fr) } for idx, fr in enumerate(self.cap.frame_rates)] } }) def bind(self, ctx, sock_type, url, public_ep, set_hwm=None): sock = ctx.socket(sock_type) if set_hwm: sock.set_hwm(set_hwm) sock.bind(url) ep = sock.last_endpoint.decode() port = ep.split(':')[-1] public_ep.split(':')[-1] public_addr = public_ep.split(':')[:-1] return sock, ':'.join(public_addr+[port])
def run_time_sync_follower(time_fn, jump_fn, slew_fn, group): """Main follower logic""" # Start Pyre node and find clock services in `pts_group` pts_group = group + '-time_sync-v1' discovery = Pyre('pupil-helper-follower') discovery.join(pts_group) discovery.start() logger.info('Joining "{}" group'.format(pts_group)) # The leaderboard keeps track of all clock services # and is used to determine the clock master leaderboard = [] follower_service = None def update_leaderboard(uuid, name, rank, port): """Add or update an existing clock service on the leaderboard""" for cs in leaderboard: if cs.uuid == uuid: if (cs.rank != rank) or (cs.port != port): remove_from_leaderboard(cs.uuid) break else: # no changes. Just leave as is return # clock service was not encountered before or has changed adding it to leaderboard cs = Clock_Service(uuid, name, rank, port) heappush(leaderboard, cs) logger.debug('<{}> added'.format(cs)) def remove_from_leaderboard(uuid): """Remove an existing clock service from the leaderboard""" for cs in leaderboard: if cs.uuid == uuid: leaderboard.remove(cs) logger.debug('<{}> removed'.format(cs)) break def evaluate_leaderboard(follower_service): """ Starts/changes/stops the time follower service according to who the current clock master is. """ if not leaderboard: logger.debug("nobody on the leader board.") if follower_service is not None: follower_service.terminate() return None current_leader = leaderboard[0] leader_ep = discovery.peer_address(current_leader.uuid) leader_addr = urlparse(leader_ep).netloc.split(':')[0] logger.info('Following <{}>'.format(current_leader)) if follower_service is None: # make new follower follower_service = Clock_Sync_Follower(leader_addr, port=current_leader.port, interval=10, time_fn=time_fn, jump_fn=jump_fn, slew_fn=slew_fn) else: # update follower_service follower_service.host = leader_addr follower_service.port = current_leader.port return follower_service try: # wait for the next Pyre event for event in discovery.events(): if event.type == 'SHOUT': # clock service announcement # ill-formatted messages will be dropped try: update_leaderboard(event.peer_uuid, event.peer_name, float(event.msg[0]), int(event.msg[1])) except Exception as e: logger.debug('Garbage raised `{}` -- dropping.'.format(e)) follower_service = evaluate_leaderboard(follower_service) elif ((event.type == 'LEAVE' and event.group == pts_group) or event.type == 'EXIT'): remove_from_leaderboard(event.peer_uuid) follower_service = evaluate_leaderboard(follower_service) except KeyboardInterrupt: pass finally: discovery.leave(pts_group) discovery.stop() if follower_service is not None: follower_service.terminate()
class Discovery: def __init__(self, my_name, my_ip, group_name): self.name = my_name self.ip = my_ip self.group = group_name # node dict is of the format ip: name # This is because a user (name) may move to a new ip. # Duplicate ip's are not allowed, but more than 1 ip may share the # same name. This is because a user may log in to multiple devices. # self.node_dict = {} self.node = Pyre(self.group) self.node.set_header(self.name, self.ip) self.node.join(self.group) self.node.start() # this runs forever for testing, but should be run as a thread self._node_update_task() """ This task will keep the node dictionary updated. The node will periodically send an update (heartbeat) control message which has the name and ip as in the header. Periodically recieve the incomming messages and update the ip name dictionary """ def _node_update_task(self): while True: cmds = self.node.recv() msg_type = cmds.pop(0) # debug prints print("NODE_MSG TYPE: %s" % msg_type) print("NODE_MSG PEER: %s" % uuid.UUID(bytes=cmds.pop(0))) print("NODE_MSG NAME: %s" % cmds.pop(0)) # headers are packed json if msg_type.decode('utf-8') == "SHOUT": print("NODE_MSG GROUP: %s" % cmds.pop(0)) elif msg_type.decode('utf-8') == "ENTER": headers = json.loads(cmds.pop(0).decode('utf-8')) print("NODE_MSG HEADERS: %s" % headers) for key in headers: print("key = {0}, value = {1}".format(key, headers[key])) print("NODE_MSG CONT: %s" % cmds) """ Get the currwnt nodes dict ip, name, group """ def get_active_nodes(self): # return the active nodes dictionary return self.node_dict def get_idle_nodes(self): return self.node_dict
Contact information: [email protected] ''' import pyre from pyre import Pyre from pyre import zhelper import zmq import uuid import logging import sys import json n = Pyre("receiver_node") print('Join group [CHAT]') n.join("CHAT") print('node START') n.start() msg_data = { "header": { "type": "CMD", "version": "0.1.0", "metamodel": "ropod-msg-schema.json", "msg_id": "0d05d0bc-f1d2-4355-bd88-edf44e2475c8", "timestamp": "2017-11-11T11:11:00Z" }, "payload": { "metamodel": "ropod-demo-cmd-schema.json", "answerList": [{
def chat_task(ctx, pipe): print("Game started") print("Name: %s" % NAME) connected_players = 1 network_players = 1 leave_counter = 0 #Set up node for the game n = Pyre("") n.set_header("header_name", NAME) #Join the group n.join(GROUPNAME) #Start broadcasting node n.start() # Set up poller poller = zmq.Poller() poller.register( pipe, zmq.POLLIN ) #Local pipe (contains commands/messages we send through terminal) poller.register(n.socket(), zmq.POLLIN) # A while loop constantly polls for new items = PULL system while True: #Wait for new message to be polled. This function blocks until there is a new message items = dict(poller.poll()) #This are messages from ourselves if pipe in items: message_pipe = pipe.recv() if message_pipe.decode('utf-8') == STOP_COMMAND: break #check if the message is a number elif message_pipe.decode( 'utf-8').isdigit() == True and yourturn == True: #variable to keep the loop going until a correct number is given status = True #check which symbol you got assigned if playerX == True: while status == True: number = int(message_pipe.decode('utf-8')) #check if the spot is free if board[number] != "X" and board[number] != "O": status = False yourturn = False print("New status board:") board[number] = "X" showboard() #check for a winning combination if checkall("X") == True: print("You win!") n.whisper(OPPONENT, str(number).encode('utf-8')) break #when there's no winning combination, it's the other player's turn else: print("Waiting for opponent's move...") #let your opponent know which number you chose n.whisper(OPPONENT, str(number).encode('utf-8')) else: print("Spot taken, try again") message_pipe = pipe.recv() else: while status == True: number = int(message_pipe.decode('utf-8')) if board[number] != "X" and board[number] != "O": status = False yourturn = False print("New status board:") board[number] = "O" showboard() if checkall("O") == True: print("You win!") n.whisper(OPPONENT, str(number).encode('utf-8')) break else: print("Waiting for opponent's move...") n.whisper(OPPONENT, str(number).encode('utf-8')) else: print("Spot taken, try again") message_pipe = pipe.recv() elif message_pipe.decode( 'utf-8').isdigit() == True and yourturn == False: print("It's not your turn, wait for your opponent's move") #if the message isn't a number, it is send as a message to your opponent else: print("Sending message to opponent: %s" % message_pipe.decode('utf-8')) n.whisper(OPPONENT, message_pipe) # Received messages from system or messages from other peers else: cmds = n.recv() #print(">>>>>>>RECEIVED MESSAGE: ", cmds) msg_type = cmds.pop(0) player_uuid = uuid.UUID(bytes=cmds.pop(0)) #OPPONENT = player_uuid #print("player uuid: ", player_uuid) msg_name = cmds.pop(0) if msg_type.decode('utf-8') == "ENTER": headers = json.loads(cmds.pop(0).decode('utf-8')) network_players += 1 if network_players == 2: print( "--------------------------------------------------------------------------------" ) print("New player discovered in network") print("Name:", headers.get("header_name")) print( "--------------------------------------------------------------------------------" ) elif msg_type.decode('utf-8') == "JOIN": connected_players += 1 #check if there's stil room for a player if connected_players > 2: leave = "No free spot left" n.whisper(player_uuid, leave.encode('utf-8')) elif connected_players == 2: print( "--------------------------------------------------------------------------------" ) print("%s joined group" % headers.get("header_name"), cmds.pop(0).decode('utf-8')) print( "--------------------------------------------------------------------------------" ) #if there are 2 players, you know your opponent: OPPONENT = player_uuid showboard() #randomly choose if you want to start assign = random.randint(0, 1) if assign == 1: player_start = True n.whisper(OPPONENT, "$$Istart".encode('utf-8')) else: player_start = False n.whisper(OPPONENT, "$$Ustart".encode('utf-8')) elif msg_type.decode('utf-8') == "WHISPER": message_opponent = cmds.pop(0).decode('utf-8') if message_opponent == "No free spot left": leave_counter += 1 #if you get the message that you must leave from 2 other players, you are the third player if leave_counter == 2: print(message_opponent) break #if the random generators both got a compatible result, the game can start elif message_opponent == "$$Istart" and player_start == False: playerX = False yourturn = False print("You are symbol O") print("You opponent may start, please wait...") elif message_opponent == "$$Ustart" and player_start == True: playerX = True yourturn = True print("You are symbol X") print("You may start") print("Where do you want to place your X?") #when the results are incompatible: try again elif message_opponent == "$$Istart" and player_start == True: assign = random.randint(0, 1) if assign == 1: player_start = True n.whisper(OPPONENT, "$$Istart".encode('utf-8')) else: player_start = False n.whisper(OPPONENT, "$$Ustart".encode('utf-8')) elif message_opponent == "$$Ustart" and player_start == False: assign = random.randint(0, 1) if assign == 1: player_start = True n.whisper(OPPONENT, "$$Istart".encode('utf-8')) else: player_start = False n.whisper(OPPONENT, "$$Ustart".encode('utf-8')) #if you receive a number, this is your opponent's move elif message_opponent.isdigit() == True: yourturn = True print( "--------------------------------------------------------------------------------" ) print("Number opponent: ", message_opponent) print("New status board:") #check for a winning combination based on which player you are if playerX == True: board[int(message_opponent)] = "O" showboard() if checkall('O') == True: print("You loose!") break #if your opponent didn't make a winning combination, it's your turn else: print("Your turn") print("Where do you want to place your X?") else: board[int(message_opponent)] = "X" showboard() if checkall('X') == True: print("You loose!") break else: print("Your turn") print("Where do you want to place your O?") #if you just received a message, print it else: print("Opponent says: ", message_opponent) elif msg_type.decode('utf-8') == "EXIT": if connected_players == 2: print("%s left network" % headers.get("header_name")) connected_players -= 1 print("Total connected players: ", connected_players) leave_counter -= 1 print("Game stopped") n.stop()
class Time_Sync(Plugin): """Synchronize time across local network. Implements the Pupil Time Sync protocol. Acts as clock service and as follower if required. See `time_sync_spec.md` for details. """ def __init__(self, g_pool, node_name=None, sync_group_prefix='default', base_bias=1.): super().__init__(g_pool) self.menu = None self.sync_group_prefix = sync_group_prefix self.discovery = None self.leaderboard = [] self.has_been_master = 0. self.has_been_synced = 0. self.tie_breaker = random.random() self.base_bias = base_bias self.master_service = Clock_Sync_Master(self.g_pool.get_timestamp) self.follower_service = None # only set if there is a better server than us self.restart_discovery(node_name) @property def sync_group(self): return self.sync_group_prefix + '-time_sync-' + __protocol_version__ @sync_group.setter def sync_group(self, full_name): self.sync_group_prefix = full_name.rsplit('-time_sync-' + __protocol_version__, maxsplit=1)[0] def init_gui(self): def close(): self.alive = False help_str = "Synchonize time of Pupil Captures across the local network." self.menu = ui.Growing_Menu('Network Time Sync') self.menu.collapsed = True self.menu.append(ui.Button('Close', close)) self.menu.append(ui.Info_Text('Protocol version: ' + __protocol_version__)) self.menu.append(ui.Info_Text(help_str)) help_str = "All pupil nodes of one group share a Master clock." self.menu.append(ui.Info_Text(help_str)) self.menu.append(ui.Text_Input('node_name', self, label='Node Name', setter=self.restart_discovery)) self.menu.append(ui.Text_Input('sync_group_prefix', self, label='Sync Group', setter=self.change_sync_group)) def sync_status(): if self.follower_service: return str(self.follower_service) else: return 'Clock Master' self.menu.append(ui.Text_Input('sync status', getter=sync_status, setter=lambda _: _, label='Status')) def set_bias(bias): if bias < 0: bias = 0. self.base_bias = bias self.announce_clock_master_info() self.evaluate_leaderboard() help_str = "The clock service with the highest bias becomes clock master." self.menu.append(ui.Info_Text(help_str)) self.menu.append(ui.Text_Input('base_bias', self, label='Master Bias', setter=set_bias)) self.menu.append(ui.Text_Input('leaderboard', self, label='Master Nodes in Group')) self.g_pool.sidebar.append(self.menu) def recent_events(self, events): should_announce = False for evt in self.discovery.recent_events(): if evt.type == 'SHOUT': try: self.update_leaderboard(evt.peer_uuid, evt.peer_name, float(evt.msg[0]), int(evt.msg[1])) except Exception as e: logger.debug('Garbage raised `{}` -- dropping.'.format(e)) self.evaluate_leaderboard() elif evt.type == 'JOIN' and evt.group == self.sync_group: should_announce = True elif (evt.type == 'LEAVE' and evt.group == self.sync_group) or evt.type == 'EXIT': self.remove_from_leaderboard(evt.peer_uuid) self.evaluate_leaderboard() if should_announce: self.announce_clock_master_info() if not self.has_been_synced and self.follower_service and self.follower_service.in_sync: self.has_been_synced = 1. self.announce_clock_master_info() self.evaluate_leaderboard() def update_leaderboard(self, uuid, name, rank, port): for cs in self.leaderboard: if cs.uuid == uuid: if (cs.rank != rank) or (cs.port != port): self.remove_from_leaderboard(cs.uuid) break else: # no changes. Just leave as is return # clock service was not encountered before or has changed adding it to leaderboard cs = Clock_Service(uuid, name, rank, port) heappush(self.leaderboard, cs) logger.debug('{} added'.format(cs)) def remove_from_leaderboard(self, uuid): for cs in self.leaderboard: if cs.uuid == uuid: self.leaderboard.remove(cs) logger.debug('{} removed'.format(cs)) break def evaluate_leaderboard(self): if not self.leaderboard: logger.debug("nobody on the leader board.") return current_leader = self.leaderboard[0] if self.discovery.uuid() != current_leader.uuid: # we are not the leader! leader_ep = self.discovery.peer_address(current_leader.uuid) leader_addr = urlparse(leader_ep).netloc.split(':')[0] if self.follower_service is None: # make new follower self.follower_service = Clock_Sync_Follower(leader_addr, port=current_leader.port, interval=10, time_fn=self.get_time, jump_fn=self.jump_time, slew_fn=self.slew_time) else: # update follower_service self.follower_service.host = leader_addr self.follower_service.port = current_leader.port return # we are the leader logger.debug("we are the leader") if self.follower_service is not None: self.follower_service.terminate() self.follower_service = None if not self.has_been_master: self.has_been_master = 1. logger.debug('Become clock master with rank {}'.format(self.rank)) self.announce_clock_master_info() def announce_clock_master_info(self): self.discovery.shout(self.sync_group, [repr(self.rank).encode(), repr(self.master_service.port).encode()]) self.update_leaderboard(self.discovery.uuid(), self.node_name, self.rank, self.master_service.port) @property def rank(self): return 4*self.base_bias + 2*self.has_been_master + self.has_been_synced + self.tie_breaker def get_time(self): return self.g_pool.get_timestamp() def slew_time(self, offset): self.g_pool.timebase.value += offset def jump_time(self, offset): ok_to_change = True for p in self.g_pool.plugins: if p.class_name == 'Recorder': if p.running: ok_to_change = False logger.error("Request to change timebase during recording ignored. Turn off recording first.") break if ok_to_change: self.slew_time(offset) logger.info("Pupil Sync has adjusted the clock by {}s".format(offset)) return True else: return False def restart_discovery(self, name): if self.discovery: if self.discovery.name() == name: return else: self.discovery.leave(self.sync_group) self.discovery.stop() self.leaderboard = [] self.node_name = name or gethostname() self.discovery = Pyre(self.node_name) # Either joining network for the first time or rejoining the same group. self.discovery.join(self.sync_group) self.discovery.start() self.announce_clock_master_info() def change_sync_group(self, new_group_prefix): if new_group_prefix != self.sync_group_prefix: self.discovery.leave(self.sync_group) self.leaderboard = [] if self.follower_service: self.follower_service.terminate() self.follower = None self.sync_group_prefix = new_group_prefix self.discovery.join(self.sync_group) self.announce_clock_master_info() def deinit_gui(self): if self.menu: self.g_pool.sidebar.remove(self.menu) self.menu = None def get_init_dict(self): return {'node_name': self.node_name, 'sync_group_prefix': self.sync_group_prefix, 'base_bias': self.base_bias} def cleanup(self): self.deinit_gui() self.discovery.leave(self.sync_group) self.discovery.stop() self.master_service.stop() if self.follower_service: self.follower_service.stop() self.master_service = None self.follower_service = None self.discovery = None
class _NetworkNode(NetworkInterface): """ Communication node Creates Pyre node and handles all communication. """ def __init__(self, format: DataFormat, context=None, name=None, headers=(), callbacks=()): self._name = name self._format = format self._headers = headers self._pyre_node = None self._context = context or zmq.Context() self._sensors_by_host = {} self._callbacks = [self._on_event] + list(callbacks) # Public NetworkInterface API @property def has_events(self) -> bool: return self.running and self._pyre_node.socket().get( zmq.EVENTS) & zmq.POLLIN @property def running(self) -> bool: return bool(self._pyre_node) @property def sensors(self) -> typing.Mapping[str, NetworkSensor]: sensors = {} for sensor in self._sensors_by_host.values(): sensors.update(sensor) return sensors @property def callbacks(self) -> typing.Iterable[NetworkEventCallback]: return self._callbacks @callbacks.setter def callbacks(self, value: typing.Iterable[NetworkEventCallback]): self._callbacks = value def start(self): # Setup node logger.debug("Starting network...") self._pyre_node = Pyre(self._name) self._name = self._pyre_node.name() for header in self._headers: self._pyre_node.set_header(*header) self._pyre_node.join(self._group) self._pyre_node.start() def whisper(self, peer, msg_p): if self._format == DataFormat.V3: return # no-op elif self._format == DataFormat.V4: self._pyre_node.whisper(peer, msg_p) else: raise NotImplementedError() def rejoin(self): for sensor_uuid, sensor in list(self.sensors.items()): self._execute_callbacks({ "subject": "detach", "sensor_uuid": sensor_uuid, "sensor_name": sensor["sensor_name"], "host_uuid": sensor["host_uuid"], "host_name": sensor["host_name"], }) self._pyre_node.leave(self._group) self._pyre_node.join(self._group) def stop(self): logger.debug("Stopping network...") self._pyre_node.leave(self._group) self._pyre_node.stop() self._pyre_node = None def handle_event(self): if not self.has_events: return event = PyreEvent(self._pyre_node) uuid = event.peer_uuid if event.type == "SHOUT" or event.type == "WHISPER": try: payload = event.msg.pop(0).decode() msg = serial.loads(payload) msg["subject"] msg["sensor_uuid"] msg["host_uuid"] = event.peer_uuid.hex msg["host_name"] = event.peer_name except serial.decoder.JSONDecodeError: logger.warning('Malformatted message: "{}"'.format(payload)) except (ValueError, KeyError): logger.warning("Malformatted message: {}".format(msg)) except Exception: logger.debug(tb.format_exc()) else: if msg["subject"] == "attach": if self.sensors.get(msg["sensor_uuid"]): # Sensor already attached. Drop event return sensor_type = SensorType.supported_sensor_type_from_str( msg["sensor_type"]) if sensor_type is None: logger.debug("Unsupported sensor type: {}".format( msg["sensor_type"])) return elif msg["subject"] == "detach": sensor_entry = self.sensors.get(msg["sensor_uuid"]) # Check if sensor has been detached already if not sensor_entry: return msg.update(sensor_entry) else: logger.debug("Unknown host message: {}".format(msg)) return self._execute_callbacks(msg) elif event.type == "JOIN": # possible values for `group_version` # - [<unrelated group>] # - [<unrelated group>, <unrelated version>] # - ['pupil-mobile'] # - ['pupil-mobile', <version>] group_version = event.group.split("-v") group = group_version[0] version = group_version[1] if len(group_version) > 1 else "0" elif event.type == "EXIT": gone_peer = event.peer_uuid.hex for host_uuid, sensors in list(self._sensors_by_host.items()): if host_uuid != gone_peer: continue for sensor_uuid, sensor in list(sensors.items()): self._execute_callbacks({ "subject": "detach", "sensor_uuid": sensor_uuid, "sensor_name": sensor["sensor_name"], "host_uuid": host_uuid, "host_name": sensor["host_name"], }) else: logger.debug("Dropping {}".format(event)) def sensor( self, sensor_uuid: str, callbacks: typing.Iterable[NetworkEventCallback] = () ) -> Sensor: try: sensor_settings = self.sensors[sensor_uuid].copy() except KeyError: raise ValueError( '"{}" is not an available sensor id.'.format(sensor_uuid)) sensor_type_str = sensor_settings.pop("sensor_type", "unknown") sensor_type = SensorType.supported_sensor_type_from_str( sensor_type_str) if sensor_type is None: raise ValueError('Sensor of type "{}" is not supported.'.format( sensor_type_str)) return Sensor.create_sensor( sensor_type=sensor_type, format=self._format, context=self._context, callbacks=callbacks, **sensor_settings, ) # Public def __str__(self): return "<{} {} [{}]>".format(__name__, self._name, self._pyre_node.uuid().hex) # Private @property def _group(self) -> str: return group_name_from_format(self._format) def _execute_callbacks(self, event): for callback in self.callbacks: callback(self, event) def _on_event(self, caller, event): if event["subject"] == "attach": subject_less = event.copy() del subject_less["subject"] host_uuid = event["host_uuid"] host_sensor = {event["sensor_uuid"]: subject_less} try: self._sensors_by_host[host_uuid].update(host_sensor) except KeyError: self._sensors_by_host[host_uuid] = host_sensor logger.debug(f'Attached {host_uuid}.{event["sensor_uuid"]}') elif event["subject"] == "detach": for host_uuid, sensors in self._sensors_by_host.items(): try: del sensors[event["sensor_uuid"]] logger.debug( f'Detached {host_uuid}.{event["sensor_uuid"]}') except KeyError: pass hosts_to_remove = [ host_uuid for host_uuid, sensors in self._sensors_by_host.items() if len(sensors) == 0 ] for host_uuid in hosts_to_remove: del self._sensors_by_host[host_uuid]
class Authority(): def __init__(self): self.node = Pyre("GAME_AUTH") self.node.set_header("AUTHORITY", "TRUE") self.node.start() self.node.join("world:position") self.node.join("ctf:teams") self.node.join("ctf:dropflag") self.node.join("ctf:gotflag") self.poller = zmq.Poller() self.poller.register(self.node.socket(), zmq.POLLIN) self.players = AuthorityPlayerManager() self.teams = {"blue": [], "red": []} self.level = SaveLevel('./assets/maps/CAPFLAG MAP NAT') red_spawn_pos = self.level.get_place(Place.RED_SPAWN) blue_spawn_pos = self.level.get_place(Place.BLUE_SPAWN) self.flags = { "blue": { "x": blue_spawn_pos[0], "y": blue_spawn_pos[1], "owner": '', "timer": 0 }, "red": { "x": red_spawn_pos[0], "y": red_spawn_pos[1], "owner": '', "timer": 0 } } self.serve() def set_teams(self): blue_players = self.teams["blue"] red_players = self.teams["red"] # Check for removed players in RED for i, playerUUID in enumerate(red_players): if playerUUID not in self.players.players.keys(): red_players.pop(i) # Check for removed players in BLUE for i, playerUUID in enumerate(blue_players): if playerUUID not in self.players.players.keys(): blue_players.pop(i) # Add new players for playerUUID, player in self.players.players.items(): if not (playerUUID in blue_players or playerUUID in red_players): if len(blue_players) > len(red_players): red_players.append(playerUUID) else: blue_players.append(playerUUID) print("Teams: " + "RED: " + ','.join(red_players) + " | BLUE: " + ','.join(blue_players)) self.node.shout("ctf:teams", bson.dumps(self.teams)) def set_flags(self, flag_info): return def update_flags(self): self.node.shout("ctf:flags", bson.dumps(self.flags)) def get_team_from_uuid(self, uuid): place = None if str(uuid) in self.teams['red']: place = Place.RED_SPAWN elif str(uuid) in self.teams['blue']: place = Place.BLUE_SPAWN return place def serve(self): clock = Clock() while True: clock.tick(60) # check network events = self.get_events() if events: try: for event in events: # Update the teams on JOIN and EXIT if event.type == 'JOIN': if event.group == 'ctf:dropflag': for team, flag in self.flags.items(): if flag['owner'] == '': self.node.shout( 'ctf:dropflag', bson.dumps({ 'x': flag['x'], 'y': flag['y'], 'team': team })) elif event.group == 'ctf:gotflag': for team, flag in self.flags.items(): if flag['owner'] != '': self.node.shout( 'ctf:gotflag', bson.dumps({ 'uuid': flag['owner'], 'team': team })) elif event.group == 'ctf:teams': self.players.set(self.node.peers()) self.set_teams() place = self.get_team_from_uuid( event.peer_uuid) pos = self.level.get_place(place) self.node.whisper( event.peer_uuid, bson.dumps({ 'type': 'teleport', 'x': pos[0], 'y': pos[1] })) elif event.type == 'EXIT': for team, flag in self.flags.items(): if flag['owner'] == str(event.peer_uuid): # flag owner is leaving, drop player = self.players.get(event.peer_uuid) flag['x'] = player.x flag['y'] = player.y flag['owner'] = '' self.node.shout( 'ctf:dropflag', bson.dumps({ 'x': flag['x'], 'y': flag['y'], 'team': team })) self.players.set(self.node.peers()) self.set_teams() elif event.type == 'SHOUT': if event.group == "world:position": new_position = bson.loads(event.msg[0]) network_player = self.players.get( event.peer_uuid) network_player.set_position(new_position) # check if flag has been captured for team, flag in self.flags.items(): if flag['owner'] != str(event.peer_uuid): continue tile = self.level.get_tile( new_position['x'], new_position['y']) if tile == TileType.RED_BLOCK and team == 'blue': # TODO: blue's flag has been captured spawn = Place.BLUE_SPAWN elif tile == TileType.BLUE_BLOCK and team == 'red': # TODO: red's flag has been captured spawn = Place.RED_SPAWN else: continue position = self.level.get_place(spawn) flag['x'] = position[0] flag['y'] = position[1] flag['owner'] = '' self.node.shout( 'ctf:dropflag', bson.dumps({ 'x': flag['x'], 'y': flag['y'], 'team': team })) if event.group == 'ctf:gotflags': flag_info = bson.loads(event.msg[0]) self.set_flags(flag_info) elif event.type == 'WHISPER': msg = bson.loads(event.msg[0]) network_player = self.players.get(event.peer_uuid) if msg['type'] == 'death_report': player = self.players.get(event.peer_uuid) previously_owned_flag = None if self.flags['blue']['owner'] == str( event.peer_uuid): previously_owned_flag = 'blue' elif self.flags['red']['owner'] == str( event.peer_uuid): previously_owned_flag = 'red' if previously_owned_flag: flag = self.flags[previously_owned_flag] flag['owner'] = '' self.node.shout( 'ctf:dropflag', bson.dumps({ 'x': player.x, 'y': player.y, 'team': previously_owned_flag })) place = self.get_team_from_uuid( event.peer_uuid) pos = self.level.get_place(place) self.node.whisper( event.peer_uuid, bson.dumps({ 'type': 'teleport', 'x': pos[0], 'y': pos[1] })) player.x = pos[0] player.y = pos[1] except Exception as e: print(e) import traceback print(traceback.format_exc()) pass for team, flag in self.flags.items(): if flag["owner"] != '': continue for uuid, player in self.players.players.items(): if flag['x'] == player.x and flag['y'] == player.y: team_place = self.get_team_from_uuid(uuid) pos = self.level.get_place(team_place) if team == 'red' and team_place == Place.RED_SPAWN or team == 'blue' and team_place == Place.BLUE_SPAWN: if player.x == pos[0] and player.y == pos[1]: continue self.node.shout( 'ctf:dropflag', bson.dumps({ 'x': pos[0], 'y': pos[1], 'team': team })) else: flag["owner"] = uuid self.node.shout( 'ctf:gotflag', bson.dumps({ 'uuid': uuid, 'team': team })) break def poll(self): return dict(self.poller.poll(0)) def peers(self): return self.node.peers() def stop(self): self.node.stop() def get_events(self): changes = self.poll() if self.node.socket() in changes and changes[ self.node.socket()] == zmq.POLLIN: events = self.node.recent_events() return events
def thread_loop(self, context, pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) logger.debug(n.socket()) poller.register(n.socket(), zmq.POLLIN) while (True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll(self.timeout)) except zmq.ZMQError: logger.warning('Socket fail.') # print(n.socket(), items) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == exit_thread: break elif message.decode('utf-8') == init_master_sync: self.timeout = 3000 else: logger.debug("Emitting to '%s' to '%s' " % (message, self.group)) n.shouts(self.group, message) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uid, name, group, msg = cmds logger.debug("'%s' shouts '%s'." % (name, msg)) self.handle_msg(name, msg) elif msg_type == "WHISPER": uid, name, msg = cmds logger.debug("'%s/' whispers '%s'." % (name, msg)) self.handle_msg_whisper(uid, name, msg, n) elif msg_type == "JOIN": uid, name, group = cmds if group == self.group: self.group_members[uid] = name self.update_gui() elif msg_type == "EXIT": uid, name = cmds try: del self.group_members[uid] except KeyError: pass else: self.update_gui() # elif msg_type == "LEAVE": # uid,name,group = cmds # elif msg_type == "ENTER": # uid,name,headers,ip = cmds # logger.warning((uid,'name',headers,ip)) elif not items: #timeout events are used for pupil sync. if self.sync_master is self: if self.sync_nodes: node_uid = self.sync_nodes.pop(0) logger.info("Synchonizing node %s" % self.group_members[node_uid]) n.whispers(uuid.UUID(bytes=node_uid), sync_time_init) else: self.timeout = None self.sync_master = None logger.info("All other Pupil nodes are sycronized.") elif self.sync_master: t0 = self.g_pool.capture.get_timestamp() n.whispers(uuid.UUID(bytes=self.sync_master), sync_time_request + '%s' % t0) else: pass logger.debug('thread_loop closing.') self.thread_pipe = None n.stop()
def thread_loop(self,context,pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) logger.debug(n.socket()) poller.register(n.socket(), zmq.POLLIN) while(True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll(self.timeout)) except zmq.ZMQError: logger.warning('Socket fail.') # print(n.socket(), items) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == exit_thread: break elif message.decode('utf-8') == init_master_sync: self.timeout = 3000 else: logger.debug("Emitting to '%s' to '%s' " %(message,self.group)) n.shouts(self.group, message) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uid,name,group,msg = cmds logger.debug("'%s' shouts '%s'."%(name,msg)) self.handle_msg(name,msg) elif msg_type == "WHISPER": uid,name,msg = cmds logger.debug("'%s/' whispers '%s'."%(name,msg)) self.handle_msg_whisper(uid,name,msg,n) elif msg_type == "JOIN": uid,name,group = cmds if group == self.group: self.group_members[uid] = name self.update_gui() elif msg_type == "EXIT": uid,name = cmds try: del self.group_members[uid] except KeyError: pass else: self.update_gui() # elif msg_type == "LEAVE": # uid,name,group = cmds # elif msg_type == "ENTER": # uid,name,headers,ip = cmds # logger.warning((uid,'name',headers,ip)) elif not items: #timeout events are used for pupil sync. if self.sync_master is self: if self.sync_nodes: node_uid = self.sync_nodes.pop(0) logger.info("Synchonizing node %s"%self.group_members[node_uid]) n.whispers(uuid.UUID(bytes=node_uid),sync_time_init) else: self.timeout = None self.sync_master = None logger.info("All other Pupil nodes are sycronized.") elif self.sync_master: t0 = self.g_pool.capture.get_timestamp() n.whispers(uuid.UUID(bytes=self.sync_master),sync_time_request+'%s'%t0) else: pass logger.debug('thread_loop closing.') self.thread_pipe = None n.stop()
def thread_loop(self, context, pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.socket(), zmq.POLLIN) front, back = zhelper.zcreate_pipe(context) poller.register(back, zmq.POLLIN) def wake_up(): #on app close this timer calls a closed socket. We simply catch it here. try: front.send('wake_up') except Exception as e: logger.debug('Orphaned timer thread raised error: %s' % e) t = Timer(self.time_sync_announce_interval, wake_up) t.daemon = True t.start() while (True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll()) except zmq.ZMQError: logger.warning('Socket fail.') continue if back in items and items[back] == zmq.POLLIN: back.recv() #timeout events are used for pupil sync. #annouce masterhood every interval time: if isinstance(self.time_sync_node, Clock_Sync_Master): n.shouts( self.group, SYNC_TIME_MASTER_ANNOUNCE + "%s" % self.clock_master_worthiness() + msg_delimeter + '%s' % self.time_sync_node.port) # synced slave: see if we should become master if we dont hear annoncement within time. elif isinstance(self.time_sync_node, Clock_Sync_Follower ) and not self.time_sync_node.offset_remains: if self.get_unadjusted_time( ) - self.last_master_announce > self.time_sync_wait_interval_short: self.time_sync_node.terminate() self.time_sync_node = Clock_Sync_Master( time_fn=self.get_time) n.shouts( self.group, SYNC_TIME_MASTER_ANNOUNCE + "%s" % self.clock_master_worthiness() + msg_delimeter + '%s' % self.time_sync_node.port) # unsynced slave or none should wait longer but eventually take over elif self.get_unadjusted_time( ) - self.last_master_announce > self.time_sync_wait_interval_long: if self.time_sync_node: self.time_sync_node.terminate() self.time_sync_node = Clock_Sync_Master( time_fn=self.get_time) n.shouts( self.group, SYNC_TIME_MASTER_ANNOUNCE + "%s" % self.clock_master_worthiness() + msg_delimeter + '%s' % self.time_sync_node.port) t = Timer(self.time_sync_announce_interval, wake_up) t.daemon = True t.start() if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == exit_thread: break else: logger.debug("Shout '%s' to '%s' " % (message, self.group)) n.shouts(self.group, message) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uuid, name, group, msg = cmds logger.debug("'%s' shouts '%s'." % (name, msg)) self._handle_msg(uuid, name, msg, n) elif msg_type == "WHISPER": uuid, name, msg = cmds logger.debug("'%s/' whispers '%s'." % (name, msg)) self._handle_msg_whisper(uuid, name, msg, n) elif msg_type == "JOIN": uuid, name, group = cmds if group == self.group: self.group_members[uuid] = name self.update_gui() elif msg_type == "EXIT": uuid, name = cmds try: del self.group_members[uuid] except KeyError: pass else: self.update_gui() # elif msg_type == "LEAVE": # uuid,name,group = cmds # elif msg_type == "ENTER": # uuid,name,headers,ip = cmds # logger.warning((uuid,'name',headers,ip)) else: pass logger.debug('thread_loop closing.') self.thread_pipe = None n.stop()
def thread_loop(self, context, pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) logger.debug(n.socket()) poller.register(n.socket(), zmq.POLLIN) while (True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll()) except zmq.ZMQError: logger.warning('Socket fail.') # print(n.socket(), items) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "EXIT_THREAD": break logger.debug("Emitting to '%s' to '%s' " % (message, self.group)) n.shouts(self.group, message) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uid, name, group, msg = cmds logger.debug("'%s' shouts '%s'." % (name, msg)) if start_rec in msg: session_name = msg.replace(start_rec, '') self.notify_all({ 'name': 'rec_should_start', 'session_name': session_name, 'network_propagate': False }) elif stop_rec in msg: self.notify_all({ 'name': 'rec_should_stop', 'network_propagate': False }) elif sync_time in msg: offset = float(msg.replace(sync_time, '')) if self.ok_to_set_timebase(): self.adjust_timebase(offset) elif msg_type == "ENTER": uid, name, headers, ip = cmds elif msg_type == "JOIN": uid, name, group = cmds if group == self.group: self.group_members[uid] = name self.update_gui() elif msg_type == "EXIT": uid, name = cmds try: del self.group_members[uid] except KeyError: pass else: self.update_gui() elif msg_type == "LEAVE": uid, name, group = cmds elif msg_tpye == "WHISPER": pass logger.debug('thread_loop closing.') self.thread_pipe = None n.stop()
class Transport(): '''Message transport mechanisms for LCAS''' def send(self, dest, ntuple): '''Send given ntuple to Transport named dest. If dest isn't listening for messages from this Transport, the message will (currently) be silently ignored.''' if self._prefix is not None: dest = self._prefix + dest self._pyre.shout(dest, json.dumps(ntuple).encode('utf-8')) # send() # Notes on subscribe # # The callback is called in the same thread that listens for pyre # messages, so the callback should start a new thread if it's # going to block or take a long time to run. # # The callback must take one positional argument, the tuple, and # can OPTIONALLY take a keyword argument (e.g. **kw). I use the # inspect module to detect this. May be too clever for my own # good. # # There can be only one callback for a given remote. If you call # subscribe again with the same remote, it raises an error. def subscribe(self, remote, callback): '''When a message is sent from a Transport named remote to this transport, call the passed callback with the ntuple as the first argument. If the callback takes **kw, it will also pass additional metadata such as the Transport name, UUID, and IP of the sender.''' if self._prefix is not None: remote = self._prefix + remote if remote in self._subscribers: raise TransportError(self, 'Transport.subscribe() was called a second time with the same remote (\"%s\"). You must call Transport.unsubscribe() before setting a new callback.'%(remote)) self._subscribers[remote] = callback # subscribe() def unsubscribe(self, remote): '''Stop listening for messages from remote.''' if self._prefix is not None: remote = self._prefix + remote if remote in self._subscribers: del self._subscribers[remote] # unsubscribe() def subscribe_all(self, callback): '''Call callback every time a message is sent from any remote Transport to this Transport.''' if self._subscribe_all is not None: raise TransportError(self, 'Transport.subscribe_all() was called a second time. You must call Transport.unsubscribe_all() before setting a new callback.') self._subscribe_all = callback # subscribe_all() def unsubscribe_all(self): self._subscribe_all = None # unsubscribe_all() # Notes on get() # # If you already subscribe to remote, temporarly overrides # the subscribe. The subscribed callback will NOT be called. # The subscription is replaced after get() returns. def get(self, remote): '''Block waiting for a message from a Transport named remote. Returns python namedtuple containing fields object, uuid, name, ip, datetime.''' if self._prefix is not None: remote = self._prefix + remote # The final python namedtuple to be returned needs to be shared # between get_callback() and get(). In python3, you can use # nonlocal, but in python2 you need a trick (storing in a # data structure). The actual value to be returned will # be ret[0]. ret = [ None ] # The event e will get set when a message is read by the # readthread. e = threading.Event() # This function is a callback used to detect the next message. # It stores the message in a Python namedtuple and sets the # event. def get_callback(tup, **kw): ret[0] = collections.namedtuple('TransportEnvelope', ['object', 'uuid', 'name', 'ip', 'datetime'])(tup, kw['uuid'], kw['name'], kw['ip'], kw['datetime']) # Inform get() that ret is ready to be returned. e.set() # get_callback() # Store the old callback, if any oldcb = self._subscribers.get(remote, None) # Set the subscription self._subscribers[remote] = get_callback # Wait for the callback to be called. e.wait() # Restore the old subscription, if any. if oldcb is not None: self._subscribers[remote] = oldcb else: del self._subscribers[remote] # Return the namedtuple. return ret[0] # get() def quit_federation(self): '''Send a quit message to all agents in this federation, and then close down the Transport.''' if self._run: self._pyre.shouts(self._globalchannel, u"QUIT") self._run = False # Wait for the readthread to finish self._readthread.join() # Tell Pyre to shut down self._pyre.stop() def is_running(self): '''Return the status of this Transport. If the Transport isn't running, you should not send it messages and the callbacks will not be called.''' return self._run ###################################################################### # All private methods below here def __init__(self, myname, port=None, prefix=None): # NOTE: Seems to be a bug in Pyre where you can't set the port. if port is not None: raise NotImplementedError('There is a bug in Pyre that prevents setting of the discovery port. If you require multiple federations of Pyre components, use prefix instead of port in Transport constructor.') # dict of remote name to callback. See subscribe method above. self._subscribers = {} # Callback for all message (or None if none registered) self._subscribe_all = None self._prefix = prefix # Attach the federation name as a prefix to both this channel # and the global channel. The global channel is currently # just used for QUIT messages. if prefix is not None: myname = prefix + myname self._globalchannel = prefix + "GLOBAL" else: self._globalchannel = "GLOBAL" self._pyre = Pyre(myname) if port is not None: self._pyre.set_port(port) self._pyre.join(myname) self._pyre.join(self._globalchannel) self._pyre.start() # Dict of (UUIDs => IP addresses) that have sent a valid ENTER message self._uuid2ip = {} self._run = True self._readthread = threading.Thread(target=self._readworker) self._readthread.start() # __init__() # Handle pyre messages. Run in self._readthread def _readworker(self): '''This method is called in a separate thread to handle messages sent over pyre. It dispataches to methods named for the pyre events (e.g. _ENTER).''' # Set up a poller so recv doesn't block. Possibly not needed # since we'll always get an event when the other agents quit, # but just in case something goes wrong, we want to be sure to # close down. poller = zmq.Poller() sock = self._pyre.socket() poller.register(sock, zmq.POLLIN) while self._run: # Wait until a message is received OR one second timeout. items = dict(poller.poll(1000)) if not (sock in items and items[sock] == zmq.POLLIN): # This should only happen if we time out. continue # There's an event waiting. Read and process it. event = self._pyre.recv() logger.debug('Transport %s-%s received event %s'%(self._pyre.uuid(), self._pyre.name(), event)) eventtype = event[0].decode('utf-8') # Sender's uuid and name sid = uuid.UUID(bytes=event[1]) name = event[2].decode('utf-8') # Make sure we've seen matching ENTER for all events if eventtype != 'ENTER' and sid not in self._uuid2ip: raise TransportProtocolError(self, 'Received event %s with no matching ENTER.'%(event)) continue if eventtype == 'ENTER': # Changed url = event[4].decode('utf-8') self._ENTER(sid, name, url) elif eventtype == 'JOIN': channel = event[3].decode('utf-8') self._JOIN(sid, name, channel) elif eventtype == 'SHOUT': channel = event[3].decode('utf-8') message = event[4].decode('utf-8') if channel == self._globalchannel and message == "QUIT": # Set ourself to stop running, close down pyre, exit # worker thread. self._run = False self._pyre.stop() break else: self._SHOUT(sid, name, channel, message) elif eventtype == 'WHISPER': message = event[3].decode('utf-8') self._WHISPER(sid, name, message) elif eventtype == 'LEAVE': channel = event[3].decode('utf-8') self._LEAVE(sid, name, channel) elif eventtype == 'EXIT': self._EXIT(sid, name) else: raise TransportProtocolError(self, 'Illegal event type in event %s'%(event)) # _readworker() # The following methods are named for the pyre event that this # instance has received. They are called automatically from the # worker thread that's listening for events. def _ENTER(self, sid, name, url): # We expect all connections to be tcp on some port. This regular # expression is used to extract the ip part. urlmatch = re.match('tcp://([0-9.]+):[0-9]+$', url) if urlmatch: ip = urlmatch.group(1) if is_valid_ip(ip): # Everything looks good. Add to list of valid uuids. self._uuid2ip[sid] = ip else: raise TransportSecurityError(self, 'Message from invalid IP address %s in ENTER %s %s %s. Check the function is_valid_ip() in Transport.py.'%(ip, sid, name, url)) else: raise TransportProtocolError(self, 'Malformed URL in ENTER %s %s %s'%(sid, name, url)) # _ENTER() def _JOIN(self, sid, name, channel): pass # _JOIN() def _SHOUT(self, sid, name, channel, message): now = datetime.datetime.now() logger.debug('In _SHOUT with %s %s %s %s'%(sid, name, channel, message)) #??? if name in self._subscribers: logger.debug('got a subscription') cb = self._subscribers[name] self._call_callback(cb, sid, name, channel, message, now) if self._subscribe_all is not None: cb = self._subscribe_all self._call_callback(cb, sid, name, channel, message, now) # _SHOUT() def _call_callback(self, cb, sid, name, channel, message, now): if inspect.getargspec(cb).keywords is None: cb(json.loads(message)) else: cb(message, uuid=sid, name=name, ip=self._uuid2ip[sid], datetime=now) # _call_callback def _WHISPER(self, sid, name, message): raise TransportProtocolError(self, 'Unexpected WHISPER from %s %s'%(sid, name)) # _WHISPER() def _LEAVE(self, sid, name, channel): pass # _LEAVE() def _EXIT(self, sid, name): # Remove sid from list of valid uuids. This should # never be an error since we check in _readworker(). del self._uuid2ip[sid]
def chat_task(ctx,pipe): print("communication started") GROUPNAME = "Quizzzzz" StopCmnd = "$$quit" OPPONENT = "opponent" print("name: %s" %NAME) connected_players = 1 # set up node for the user n = Pyre(GROUPNAME) n.set_header('Name', NAME) # join the groupchat n.join(GROUPNAME) #print("UUID %s" %n.uuid()) # start broadcasting signal n.start() # set up poller poller = zmq.Poller() poller.register(pipe,zmq.POLLIN) poller.register(n.socket(),zmq.POLLIN) # looping constantly to recieve messages while True: items = dict(poller.poll()) if pipe in items: message = pipe.recv() if message.decode('utf-8') == StopCmnd: break # uppercase letters for question to whole group elif message.decode('utf-8').isupper() == True: print("Question is: %s" %message) n.shouts(GROUPNAME,"Question to group is: %s" %message.decode('utf-8')) answer = 0 # lowercase to last person who asked question in the group elif message.decode('utf-8').islower() == True: message = NAME + "'s answer is=" + message n.whisper(PEER,message) else: print("please don't mix up or lowercase or use not only numbers") else: msgrecv = n.recv() #print(msgrecv) msg_type = msgrecv.pop(0) msg_sender = uuid.UUID(bytes=msgrecv.pop(0)) PEER = msg_sender msg_name = msgrecv.pop(0) if msg_type.decode('utf-8') == "ENTER": headers = json.loads(msgrecv.pop(0).decode('utf-8')) print("New player discovered in network") print("New player = %s " %headers.get("Name")) elif msg_type.decode('utf-8') == "JOIN": print("New player has joined the group") print("New player = %s" %headers.get("Name")) connected_players += 1 print("#players = %s" %connected_players) elif msg_type.decode('utf-8') == "SHOUT": print(msgrecv.pop(1)) elif msg_type.decode('utf-8') == "WHISPER": if msgrecv[0] == "You have to ask next question": print("You have to ask next question") n.shout(GROUPNAME, "%s is new quizmaster" %NAME) answer = 0 else: print(msgrecv.pop(0)) answer +=1 if answer == connected_players -1: #choosing new quizmaster randomly players = n.peers() next_master = players.pop(random.randint(0,connected_players-2)) n.whisper(next_master,"You have to ask next question") print("Left current game") n.stop()
class ZyreToZMQModule: """ The ZyreToZMQModule Base Class """ def __init__(self,ctx = None,name = "Default",headers=None,groups=None,config_file=None,polling_timeout = 1,sim_time=2): self.logger = logging.getLogger(name) self.logger.setLevel(logging.DEBUG) # create the console output logging sh = logging.StreamHandler() sh.setLevel(logging.INFO) # create a logger writing into a log file fh = logging.FileHandler(name + ".log") fh.setLevel(logging.DEBUG) # create formatter and add it to the handlers # see https://docs.python.org/2/library/logging.html#logrecord-attributes for what can be logged fh.setFormatter(logging.Formatter('Name: %(name)s, ProcessName: %(processName)s, ThreadName: %(threadName)s, Module: %(module)s, FunctionName: %(funcName)s, LineNo: %(lineno)d, Level: %(levelname)s, Msg: %(message)s')) #sh.setFormatter(logging.Formatter('Module: %(module)s, FunctionName: %(funcName)s, LineNo: %(lineno)d, Level: %(levelname)s, Msg: %(message)s')) sh.setFormatter(logging.Formatter('Name: %(name)s, %(module)s/%(funcName)s[%(levelname)s]: %(message)s (lineno:%(lineno)d)')) # add the handlers to logger self.logger.addHandler(sh) self.logger.addHandler(fh) self.logger.propagate = False # don't pass messages to parent loggers if not type(ctx) == zmq.sugar.context.Context: self.logger.warn("Created ZMQ context. Please supply a ZMQ context next time.") ctx = zmq.Context() self.ctx = ctx if not type(name) == str: name = "Default" self.logger.warn("Please provide a the name as a string. Setting name to default: %s." % name) self.name = name if not headers: self.logger.warn("Please provide a model and other header information.") headers = {} self.headers = headers if not groups: groups = ["SHERPA"] self.logger.warn("Please provide a list with group names to which it will listen. Will set it to default: %s" %groups) self.groups = groups if not config_file: # will be opened during configuration self.logger.error("No config file provided for initial configuration") exit() self.config_file = config_file self.config = None self.alive = True # used for exiting once the node is stopped self.line_controller = None # stores uid of line controller this module is listening to (to avoid several line controllers) self.com_timeout = polling_timeout # time_out in msec after which poller returns self.sim_time = sim_time # time in msec self.inbox = [] self.outbox = [] # Node setup self.node = Pyre(self.name) for key in self.headers: self.node.set_header(key,self.headers[key]) for group in self.groups: self.node.join(group) #self.node.set_verbose() self.node.start() # Socket setup self.poller = zmq.Poller() self.poller.register(self.node.socket(), zmq.POLLIN) port = "12911" self.zmq_socket = self.ctx.socket(zmq.PUB) self.zmq_socket.bind("tcp://*:%s" % port) self.run() def run(self): """ Running loop of this process: [COMMUNICATION] Check communication channels and parse all messages. """ while self.alive: try: #[COMMUNICATION] self.communication() #[LOGGING] #self.logging() time.sleep(1) except (KeyboardInterrupt, SystemExit): break self.node.stop() def communication(self): """ This function handles the communication """ # Check if communication is ready if not self.poller: self.logger.warn("No communication channels yet.") # Process input items = dict(self.poller.poll(self.com_timeout)) # Get input from Pyre socket and put it in inbox which is processed in the following steps #logger.debug("Start processing incoming messages") if self.node.socket() in items and items[self.node.socket()] == zmq.POLLIN: self.logger.info("Received %d msgs." % len(items)) #print "msg arrived. inbox len %d" % len(self.inbox) msg_frame = self.node.recv() msg_type = msg_frame.pop(0) peer_uid = uuid.UUID(bytes=msg_frame.pop(0)) peer_name = msg_frame.pop(0) self.logger.info("Msg type: %s" % msg_type) self.logger.info("Sender: %s" % peer_name) # For shout and whisper take message payload and put it into inbox assuming it is correct # For the other zyre msgs create a JSON obj and put that into inbox # TODO: add validation if msg_type == "SHOUT": group = msg_frame.pop(0) msg = json.loads(msg_frame.pop(0)) msg["sender_UUID"] = peer_uid msg["sender_name"] = peer_name # self.inbox.append(msg) self.outbox.append(msg) elif msg_type == "WHISPER": msg = json.loads(msg_frame.pop(0)) msg["sender_UUID"] = peer_uid msg["sender_name"] = peer_name self.inbox.append(msg) # don't care about join and leave messages; if necessary, split to have separate events # elif msg_type == "LEAVE" or msg_type == "JOIN": # group = msg_frame.pop(0) # event = json.dumps({"metamodel": "http://www.sherpa-project.eu/examples/sherpa_msgs", # "model": "http://www.sherpa-project.eu/examples/sherpa_msgs/zyre_events", # "type": "leave/join", # "sender_UUID": peer_uid, # "sender_name": peer_name, # "payload": {} # }) # self.inbox.append(event) elif msg_type == "ENTER": headers = json.loads(msg_frame.pop(0)) event = {"metamodel": "http://www.sherpa-project.eu/examples/sherpa_msgs", "model": "http://www.sherpa-project.eu/examples/sherpa_msgs/zyre_events", "type": "enter", "sender_UUID": peer_uid, "sender_name": peer_name, "payload": {"header": headers} } self.inbox.append(event) elif msg_type == "EXIT": event = {"metamodel": "http://www.sherpa-project.eu/examples/sherpa_msgs", "model": "http://www.sherpa-project.eu/examples/sherpa_msgs/zyre_events", "type": "exit", "sender_UUID": peer_uid, "sender_name": peer_name, "payload": {} } self.inbox.append(event) # Process output and send all msgs there until it is empty, but only if a line controller is connected. if self.outbox: #only do if there really is something in the outbox #if self.lcsm.sm.curr_state._name == "Idle" or self.lcsm.sm.curr_state._name == "Busy": if true: self.logger.info("Start processing messages in outbox. Number of msgs in outbox: %d" % len(self.outbox)) while self.outbox: # since we assume all msgs conform to the sherpa_msgs JSON model, simply shout them out # TODO: add validation msg = self.outbox.pop() if type(msg) == dict: self.logger.info("outbox msg type: " + msg["type"]) self.node.shout("SHERPA", json.dumps(msg)) #WM message msg_wm_update = { "@worldmodeltype": "RSGUpdate", "operation": "CREATE", "node": { "@graphtype": "Group", "id": "ff483c43-4a36-4197-be49-de829cdd66c8", "attributes": [ {"key": "name", "value": "Task Specification Tree"}, {"key": "tst:envtst", "value": msg }, ], }, "parentId": "e379121f-06c6-4e21-ae9d-ae78ec1986a1", } print ("===") print (json.dumps(msg_wm_update)) self.zmq_socket.send_string(json.dumps(msg_wm_update)) else: self.logger.warn("Message is not a dict! Serialization is done here! Msg: \n" + str(msg)) else: self.logger.info("Can't send messages in outbox. Module not ready.")
class Network: hosting: bool = False def __init__(self): self.open() def get_all_groups(self) -> List[str]: """Get the names of groups that can be joined.""" groups = [] for peer in self.node.peers(): group = self.node.peer_header_value(peer, 'hosting') if group != None and len(group) > 0: groups.append(group) return groups def get_our_group(self) -> Union[str, None]: """What is the name of the group we're in or hosting?""" our_groups = self.node.own_groups() our_groups.remove('untangled2018') if len(our_groups) == 0: return None return our_groups[0] def is_in_group(self) -> bool: """Are we in or hosting a group?""" return self.get_our_group() != None def is_hosting(self) -> bool: """Are we hosting?""" return self.hosting def join_group(self, group: str) -> None: """Join a group of given name (assumes you are not in a group already).""" if group not in self.get_all_groups(): raise ValueError('Group named "%s" does not exist'.format(group)) if self.is_in_group(): raise ValueError( 'You must leave the previous group before you join another') self.node.join(group) def leave_group(self) -> None: """Leave any joined group or stop hosting.""" self.hosting = False if not self.is_in_group(): raise ValueError('You are not in a group') for group in self.node.own_groups(): self.node.leave(group) def host_group(self, name: str) -> None: """Host a group of given name.""" if name in self.get_all_groups(): raise ValueError('A group of the given name already exists') if self.is_in_group(): raise ValueError('Cannot host whilst in a group') self.node.set_header('hosting', name) self.hosting = True self.node.join(name) def open(self) -> None: """Create a new pyre instance and join untangled.""" self.node = Pyre() self.node.start() self.node.join('untangled2018') # used to get our messages self.poller = zmq.Poller() self.poller.register(self.node.socket(), zmq.POLLIN) def get_id(self) -> str: """Get our id, as a unique node on the network.""" return self.node.uuid() def is_me(self, player_id) -> bool: """See if a given id is ours.""" return self.get_id() == player_id def close(self) -> None: """Disconnect from everything""" self.node.stop() def get_messages(self): """See what has been sent to us: who has joined, what have people said, etc""" # what has changed changes = dict(self.poller.poll(0)) # are these the changes we subscribed for if self.node.socket() in changes and changes[ self.node.socket()] == zmq.POLLIN: msgs = self.node.recent_events() return msgs # nothing to return return [] def pull_game(self, game): """Update our game state based on what other people tell us.""" for msg in self.get_messages(): # is it relevant to us? if msg.group != self.get_our_group(): continue if msg.type == 'SHOUT': entities = bson.loads(msg.msg[0]) if 'ids' in entities: keys = entities['ids'] cur_keys = list(game.entities.keys()) diff = list(set(cur_keys) - set(keys)) for key in diff: del game.entities[key] entities = entities['components'] for key, changed_comps in entities.items(): key = uuid.UUID(key) if key not in game.entities: game.entities[key] = {} entity = game.entities[key] for compname, component in changed_comps.items(): try: clas = components.__dict__[compname] if clas in entity: entity[clas] = entity[clas].replace( **component) else: entity[clas] = clas(**component) entity[clas].observed_changes() except Exception: print( 'Error updating component, is everyone in the group on the same version?', file=sys.stdout) elif self.is_hosting(): if msg.type == 'JOIN': game.on_player_join(msg.peer_uuid) self.push_game(game, initial=True) elif msg.type == 'EXIT' or msg.type == "LEAVE": game.on_player_quit(msg.peer_uuid) def push_game(self, game, initial=False): """Tell others how we've changed the game state.""" if len(self.node.peers_by_group(self.get_our_group())) == 0: # Nobody else to talk to return entities = {'components': {}} if self.is_hosting(): entities = {'ids': [], 'components': {}} for key, entity in game.entities.items(): changed_comps = {} for component in entity.values(): if component.is_networked() and (initial or component.has_changed()): changed_comps[component.get_name()] = component.as_dict() component.observed_changes() if 'ids' in entities: entities['ids'].append(key) entities['components'][str(key)] = changed_comps self.node.shout(self.get_our_group(), bson.dumps(entities))
def handle_msg(uuid,name,msg,node): print UUID(bytes=uuid),name,msg if __name__ == '__main__': logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger("pyre") logger.setLevel(logging.INFO) logger = logging.getLogger() logger.setLevel(logging.DEBUG) ctx = zmq.Context() n = Pyre("Script") n.join('default group') n.start() poller = zmq.Poller() poller.register(n.socket(), zmq.POLLIN) try: while(True): items = dict(poller.poll(timeout=1000)) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uuid,name,group,msg = cmds handle_msg(uuid,name,msg,n) elif msg_type == "WHISPER":
def thread_loop(self,context,pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) logger.debug(n.socket()) poller.register(n.socket(), zmq.POLLIN) while(True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll()) except zmq.ZMQError: logger.warning('Socket fail.') # print(n.socket(), items) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "EXIT_THREAD": break logger.debug("Emitting to '%s' to '%s' " %(message,self.group)) n.shouts(self.group, message) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uid,name,group,msg = cmds logger.debug("'%s' shouts '%s'."%(name,msg)) self.handle_msg(name,msg) elif msg_type == "WHISPER": pass # uid,name,group,msg = cmds # logger.debug("'%s' whispers '%s'."%(name,msg)) # self.handle_msg(name,msg) elif msg_type == "JOIN": uid,name,group = cmds if group == self.group: self.group_members[uid] = name self.update_gui() elif msg_type == "EXIT": uid,name = cmds try: del self.group_members[uid] except KeyError: pass else: self.update_gui() # elif msg_type == "LEAVE": # uid,name,group = cmds # elif msg_type == "ENTER": # uid,name,headers,ip = cmds logger.debug('thread_loop closing.') self.thread_pipe = None n.stop()
class Time_Sync(Plugin): """Synchronize time across local network. Implements the Pupil Time Sync protocol. Acts as clock service and as follower if required. See `time_sync_spec.md` for details. """ icon_chr = chr(0xEC15) icon_font = "pupil_icons" def __init__(self, g_pool, node_name=None, sync_group_prefix="default", base_bias=1.0): super().__init__(g_pool) self.sync_group_prefix = sync_group_prefix self.discovery = None self.leaderboard = [] self.has_been_master = 0.0 self.has_been_synced = 0.0 self.tie_breaker = random.random() self.base_bias = base_bias self.sync_group_members = {} self.master_service = Clock_Sync_Master(self.g_pool.get_timestamp) self.follower_service = None # only set if there is a better server than us self.restart_discovery(node_name) @property def sync_group(self): return self.sync_group_prefix + "-time_sync-" + __protocol_version__ @sync_group.setter def sync_group(self, full_name): self.sync_group_prefix = full_name.rsplit("-time_sync-" + __protocol_version__, maxsplit=1)[0] def init_ui(self): self.add_menu() self.menu.label = "Network Time Sync" help_str = "Synchonize time of Pupil Captures across the local network." self.menu.append( ui.Info_Text("Protocol version: " + __protocol_version__)) self.menu.append(ui.Info_Text(help_str)) help_str = "All pupil nodes of one group share a Master clock." self.menu.append(ui.Info_Text(help_str)) self.menu.append( ui.Text_Input("node_name", self, label="Node Name", setter=self.restart_discovery)) self.menu.append( ui.Text_Input( "sync_group_prefix", self, label="Sync Group", setter=self.change_sync_group, )) def sync_status(): if self.follower_service: return str(self.follower_service) else: return "Clock Master" self.menu.append( ui.Text_Input("sync status", getter=sync_status, setter=lambda _: _, label="Status")) def set_bias(bias): if bias < 0: bias = 0.0 self.base_bias = bias self.announce_clock_master_info() self.evaluate_leaderboard() help_str = "The clock service with the highest bias becomes clock master." self.menu.append(ui.Info_Text(help_str)) self.menu.append( ui.Text_Input("base_bias", self, label="Master Bias", setter=set_bias)) self.menu.append( ui.Text_Input("leaderboard", self, label="Master Nodes in Group")) self.sync_group_members_menu = ui.Growing_Menu("Sync Group Members") self.menu.append(self.sync_group_members_menu) def recent_events(self, events): should_announce = False for evt in self.discovery.recent_events(): if evt.type == "SHOUT": try: self.update_leaderboard(evt.peer_uuid, evt.peer_name, float(evt.msg[0]), int(evt.msg[1])) except Exception as e: logger.debug("Garbage raised `{}` -- dropping.".format(e)) self.evaluate_leaderboard() elif evt.type == "JOIN" and evt.group == self.sync_group: should_announce = True self.insert_sync_group_member(evt.peer_uuid, evt.peer_name) elif (evt.type == "LEAVE" and evt.group == self.sync_group) or evt.type == "EXIT": self.remove_from_leaderboard(evt.peer_uuid) self.evaluate_leaderboard() self.remove_sync_group_member(evt.peer_uuid) if should_announce: self.announce_clock_master_info() if (not self.has_been_synced and self.follower_service and self.follower_service.in_sync): self.has_been_synced = 1.0 self.announce_clock_master_info() self.evaluate_leaderboard() def update_leaderboard(self, uuid, name, rank, port): for cs in self.leaderboard: if cs.uuid == uuid: if (cs.rank != rank) or (cs.port != port): self.remove_from_leaderboard(cs.uuid) break else: # no changes. Just leave as is return # clock service was not encountered before or has changed adding it to leaderboard cs = Clock_Service(uuid, name, rank, port) heappush(self.leaderboard, cs) logger.debug("{} added".format(cs)) def remove_from_leaderboard(self, uuid): for cs in self.leaderboard: if cs.uuid == uuid: self.leaderboard.remove(cs) logger.debug("{} removed".format(cs)) break def evaluate_leaderboard(self): if not self.leaderboard: logger.debug("nobody on the leader board.") return current_leader = self.leaderboard[0] if self.discovery.uuid() != current_leader.uuid: # we are not the leader! leader_ep = self.discovery.peer_address(current_leader.uuid) leader_addr = urlparse(leader_ep).netloc.split(":")[0] if self.follower_service is None: # make new follower self.follower_service = Clock_Sync_Follower( leader_addr, port=current_leader.port, interval=10, time_fn=self.get_time, jump_fn=self.jump_time, slew_fn=self.slew_time, ) else: # update follower_service self.follower_service.host = leader_addr self.follower_service.port = current_leader.port return # we are the leader logger.debug("we are the leader") if self.follower_service is not None: self.follower_service.terminate() self.follower_service = None if not self.has_been_master: self.has_been_master = 1.0 logger.debug("Become clock master with rank {}".format(self.rank)) self.announce_clock_master_info() def insert_sync_group_member(self, uuid, name): member_text = ui.Info_Text(name) self.sync_group_members[uuid] = member_text self.sync_group_members_menu.append(member_text) self.sync_group_members_menu.elements.sort( key=lambda text_field: text_field.text) def insert_all_sync_group_members_from_group(self, group): for uuid in self.discovery.peers_by_group(group): name = self.discovery.get_peer_name(uuid) self.insert_sync_group_member(uuid, name) def remove_all_sync_group_members(self): for uuid in list(self.sync_group_members.keys()): self.remove_sync_group_member(uuid) def remove_sync_group_member(self, uuid): try: self.sync_group_members_menu.remove(self.sync_group_members[uuid]) del self.sync_group_members[uuid] except KeyError: logger.debug("Peer has already been removed from members list.") def announce_clock_master_info(self): self.discovery.shout( self.sync_group, [ repr(self.rank).encode(), repr(self.master_service.port).encode() ], ) self.update_leaderboard(self.discovery.uuid(), self.node_name, self.rank, self.master_service.port) @property def rank(self): return (4 * self.base_bias + 2 * self.has_been_master + self.has_been_synced + self.tie_breaker) def get_time(self): return self.g_pool.get_timestamp() def slew_time(self, offset): self.g_pool.timebase.value += offset def jump_time(self, offset): ok_to_change = True for p in self.g_pool.plugins: if p.class_name == "Recorder": if p.running: ok_to_change = False logger.error( "Request to change timebase during recording ignored. Turn off recording first." ) break if ok_to_change: self.slew_time(offset) logger.info( "Pupil Sync has adjusted the clock by {}s".format(offset)) return True else: return False def restart_discovery(self, name): if self.discovery: if self.discovery.name() == name: return else: self.remove_all_sync_group_members() self.discovery.leave(self.sync_group) self.discovery.stop() self.leaderboard = [] self.node_name = name or gethostname() self.discovery = Pyre(self.node_name) # Either joining network for the first time or rejoining the same group. self.discovery.join(self.sync_group) self.discovery.start() self.announce_clock_master_info() def change_sync_group(self, new_group_prefix): if new_group_prefix != self.sync_group_prefix: self.remove_all_sync_group_members() self.discovery.leave(self.sync_group) self.leaderboard = [] if self.follower_service: self.follower_service.terminate() self.follower = None self.sync_group_prefix = new_group_prefix self.discovery.join(self.sync_group) self.insert_all_sync_group_members_from_group(self.sync_group) self.announce_clock_master_info() def deinit_ui(self): for uuid in list(self.sync_group_members.keys()): self.remove_sync_group_member(uuid) self.remove_menu() def get_init_dict(self): return { "node_name": self.node_name, "sync_group_prefix": self.sync_group_prefix, "base_bias": self.base_bias, } def cleanup(self): self.discovery.leave(self.sync_group) self.discovery.stop() self.master_service.stop() if self.follower_service: self.follower_service.stop() self.master_service = None self.follower_service = None self.discovery = None
def chat_task(ctx, pipe): print("-----CAR PEER COMMUNICATION STARTED-----") print("Manufacturer: ", MANUFACTURER, " - Model: ", MODEL) connected_cars = 0 #Set up node for the car n = Pyre("") n.set_header("manufacturer", MANUFACTURER) n.set_header("model", MODEL) #Join the group 'chat' n.join(GROUPNAME) #Start broadcasting node n.start() # Set up poller poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) #Local pipe (contains commands/messages we send through terminal) poller.register(n.socket(), zmq.POLLIN) # A while loop constantly polls for new items = PULL system while True: #Wait for new message to be polled. This function blocks until there is a new message items = dict(poller.poll()) #This are messages from ourselves, that we want to shout on the network if pipe in items: message = pipe.recv() # User stopped car if message.decode('utf-8') == STOP_COMMAND: break print(">>>>>> Sending out shout: %s" % message) n.shouts(GROUPNAME, message.decode('utf-8')) # Received messages from system or messages from other peers else: cmds = n.recv() print("--------------------------------------------------------------------------------") #print(">>>>>>>RECEIVED MESSAGE: ", cmds) msg_type = cmds.pop(0) car_uuid = uuid.UUID(bytes=cmds.pop(0)) msg_name = cmds.pop(0) if msg_type.decode('utf-8') == "ENTER": headers = json.loads(cmds.pop(0).decode('utf-8')) print(">>>> NEW CAR DISCOVERED IN NETWORK") print("---Manufacturer:", headers.get("manufacturer"), "--- Model:", headers.get("model")) elif msg_type.decode('utf-8') == "JOIN": print(">>>> NEW CAR JOINED GROUP <<", cmds.pop(0).decode('utf-8'),">>") connected_cars += 1 elif msg_type.decode('utf-8') == "SHOUT": print(">>>> RECEIVED SHOUT IN %s" % cmds.pop(0)) print("---Msg: %s" % cmds.pop(0)) elif msg_type.decode('utf-8') == "EXIT": print(">>>> CAR LEFT NETWORK") connected_cars -= 1 print("---Total connected cars: ", connected_cars) print("---Car_UUID: ", car_uuid) #print("---NODE_MSG REMAINING: %s" % cmds) print("-----CAR COMMUNICATION STOPPED-----") n.stop()
def rethinkdb_writer(ctx, pipe): # Database setup with open('../configuration.json') as data_file: configuration = json.load(data_file) group_name = configuration['zyreMediator']['group'] n = Pyre(configuration['zyreMediator']['name']) n.set_interface('usb0') n.set_header('TYPE', configuration['zyreMediator']['type']) n.join(group_name) n.start() # Zyre setup poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) poller.register(n.inbox, zmq.POLLIN) database_configuration = configuration['database']['mongoDB'] mongo_connection = MongoClient(database_configuration['host'], database_configuration['port']) meteor = mongo_connection['meteor'] # Add this module to the database meteor['modules'].insert([{ '_id': str(n.uuid()), 'name': n.name(), 'type': configuration['zyreMediator']['type'], 'parent': None }]) ready_message = { 'type': 'state', 'senderId': str(n.uuid()), 'payload': 2 } def logMessage(message_to_log): message_to_log['timestamp'] = datetime.datetime.utcnow() meteor['events'].insert_one(message_to_log) del message_to_log['timestamp'] del message_to_log['_id'] n.shout(group_name, json.dumps(ready_message)) logMessage(ready_message) module_name_to_uid_map = {} while True: items = dict(poller.poll(10)) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == '$$STOP': break if n.inbox in items and items[n.inbox] == zmq.POLLIN: msg_frame = n.recv() msg_type = msg_frame.pop(0) peer_uid = uuid.UUID(bytes=msg_frame.pop(0)) peer_name = msg_frame.pop(0) print('NODE_MSG TYPE: %s' % msg_type) print('NODE_MSG PEER: %s' % str(peer_uid)) print('NODE_MSG NAME: %s' % peer_name) if msg_type.decode('utf-8') == 'ENTER': headers = json.loads(msg_frame.pop(0)) try: module_type = headers['type'] except KeyError: print("Your header doesn't contain your type of module") module_type = 'unknown' try: parent_module_id = headers['parentId'] except KeyError: print("The header doesn't contain the module's parent id") parent_module_id = None # creates an entry with all known information about the robot # in the database if the robot is not in the database meteor['modules'].insert_one({ '_id': str(peer_uid), 'name': peer_name, 'type': module_type, 'parent': parent_module_id }) module_name_to_uid_map[peer_name] = str(peer_uid) elif msg_type.decode('utf-8') == 'EXIT': meteor['modules'].remove({'_id': str(peer_uid)}) elif msg_type.decode('utf-8') == 'SHOUT': # write message to database group = msg_frame.pop(0) try: data = json.loads(msg_frame[0]) except: data = {} print 'Invalid JSON string' # print data data['senderId'] = str(peer_uid) logMessage(data) elif msg_type.decode('utf-8') == 'WHISPER': # write message to database try: data = json.loads(msg_frame[0]) except: print 'Invalid JSON string' logMessage(data) meteor['modules'].remove({'_id': str(n.uuid())}) n.stop()
def thread_loop(self, context, pipe): n = Pyre(self.name) n.join(self.group) n.start() poller = zmq.Poller() poller.register(pipe, zmq.POLLIN) logger.debug(n.socket()) poller.register(n.socket(), zmq.POLLIN) while (True): try: #this should not fail but it does sometimes. We need to clean this out. # I think we are not treating sockets correclty as they are not thread-save. items = dict(poller.poll()) except zmq.ZMQError: logger.warning('Socket fail.') # print(n.socket(), items) if pipe in items and items[pipe] == zmq.POLLIN: message = pipe.recv() # message to quit if message.decode('utf-8') == "EXIT_THREAD": break logger.debug("Emitting to '%s' to '%s' " % (message, self.group)) n.shouts(self.group, message) if n.socket() in items and items[n.socket()] == zmq.POLLIN: cmds = n.recv() msg_type = cmds.pop(0) msg_type = msg_type.decode('utf-8') if msg_type == "SHOUT": uid, name, group, msg = cmds logger.debug("'%s' shouts '%s'." % (name, msg)) self.handle_msg(name, msg) elif msg_type == "WHISPER": pass # uid,name,group,msg = cmds # logger.debug("'%s' whispers '%s'."%(name,msg)) # self.handle_msg(name,msg) elif msg_type == "JOIN": uid, name, group = cmds if group == self.group: self.group_members[uid] = name self.update_gui() elif msg_type == "EXIT": uid, name = cmds try: del self.group_members[uid] except KeyError: pass else: self.update_gui() # elif msg_type == "LEAVE": # uid,name,group = cmds # elif msg_type == "ENTER": # uid,name,headers,ip = cmds logger.debug('thread_loop closing.') self.thread_pipe = None n.stop()