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()
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 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
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()
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 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()
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 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()
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()
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()) 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 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 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
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
def network_manager(self, ctx, write_pipe, node_name, overlay_network_name, read_pipe): # create the poller to wait for messages from pipes and network poller = zmq.Poller() poller.register(write_pipe, zmq.POLLIN) # create the Pyre node object node = Pyre(node_name + str(uuid.uuid4())) # register node to the network, start it and register for events with # the poller. node.join(overlay_network_name) node.start() poller.register(node.socket(), zmq.POLLIN) while (True): # do stuff, aka wait and decode messages items = dict(poller.poll()) if write_pipe in items and items[write_pipe] == zmq.POLLIN: # here is where the thread receives internal data # check if we have to send something outside # or eventually die gracefully message = write_pipe.recv() # here I have a Command + a FardNetworkData object decoded_message = pickle.loads(message) command = decoded_message[0] network_data = decoded_message[1] if command == "$$STOP": # message to quit here break elif command == "$$GET_PEERS": # only synchronous command, retrieves the peers inside the # network of tasks. group = network_data.group peers = node.peers_by_group(group) list_of_peers = [] for peer in peers: list_of_peers.append(str(peer)) write_pipe.send(pickle.dumps(str(";".join(list_of_peers)))) elif command == "$$SEND_MESSAGE" in decoded_message: # send message to a single peer using Pyre # if requested, send back the message to the same node that # sent it. peer = network_data.peer network_data.sender_peer = str(node.uuid()) network_data.message_type = "peer" node.whisper(uuid.UUID(peer), pickle.dumps(network_data)) if network_data.auto_send and peer == network_data.sender_peer: read_pipe.send(pickle.dumps(network_data)) elif command == "$$SEND_TASK_MESSAGE": # send message to a group of identical tasks using Pyre. # Currently implemented with a shout that is ignored by a # receiver if the task name is different from his. # if requested, send back the message to the same node that # sent it. network_data.sender_peer = str(node.uuid()) network_data.message_type = "task" node.shout(group, pickle.dumps(network_data)) if network_data.auto_send: read_pipe.send(pickle.dumps(network_data)) elif command == "$$SEND_GROUP_MESSAGE": # send message to the whole application using Pyre # if requested, send back the message to the same node that # sent it. group = network_data.group network_data.sender_peer = str(node.uuid()) network_data.message_type = "group" node.shout(group, pickle.dumps(network_data)) if network_data.auto_send: read_pipe.send(pickle.dumps(network_data)) else: # here is where the thread receives data from the outside # decode messages and reroute them accordingly cmds = node.recv() msg_type = cmds.pop(0).decode('utf-8') peer_uuid = uuid.UUID(bytes=cmds.pop(0)) sender_node_name = cmds.pop(0).decode('utf-8') if msg_type == "SHOUT": group = cmds.pop(0).decode('utf-8') read_pipe.send(cmds.pop(0)) elif msg_type == "WHISPER": read_pipe.send(cmds.pop(0)) # elif msg_type == "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) node.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 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 _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()) 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 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 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 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 %s'%self.cap.name) # init pyre self.network = Pyre(socket.gethostname()+self.cap.name[-4:]) self.network.start() logger.info('Bridging under "%s"'%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('pupil-mobile', self.sensor_attach_json()) 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('pupil-mobile', json.dumps({ 'subject' : 'detach', 'sensor_uuid': self.network.uuid().hex })) logger.info('Leaving bridging loop...') def publish_frame(self): frame = self.cap.get_frame_robust() now = int(time.time()*1000000) index = self.data_seq self.data_seq += 1 self.data_seq %= sequence_limit jpeg_buffer = frame.jpeg_buffer meta_data = struct.pack('<LLLLQLL', 0x10, frame.width, frame.height, index, now, jpeg_buffer.size, 0) self.data.send_multipart([self.network.uuid().hex, meta_data, jpeg_buffer]) def poll_network(self): while has_data(self.network.socket()): event = PyreEvent(self.network) if event.type == 'JOIN' and event.group == 'pupil-mobile': self.network.whisper(event.peer_uuid, self.sensor_attach_json()) def poll_cmd_socket(self): while has_data(self.cmd): sensor, cmd_str = self.cmd.recv_multipart() try: cmd = json.loads(cmd_str) except Exception as e: logger.debug('Could not parse received cmd: %s'%cmd_str) else: logger.debug('Received cmd: %s'%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, self.frame_size_control_json()]) self.note.send_multipart([ self.network.uuid().hex, self.frame_rate_control_json()]) 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': '%ix%i'%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'%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 port = ep.split(':')[-1] public_ep.split(':')[-1] public_addr = public_ep.split(':')[:-1] return sock, ':'.join(public_addr+[port])
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 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()
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()
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.")
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 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))
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": uuid,name,msg = cmds handle_msg(uuid,name,msg,n) elif msg_type == "JOIN": uid,name,group = cmds logger.debug("'%s' joined with uid: %s"%(name,uid)) elif msg_type == "EXIT": uid,name = cmds logger.debug("'%s' left with uid: %s"%(name,uid)) except (KeyboardInterrupt, SystemExit): print 'User exit' 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()
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()
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.")