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()
示例#2
0
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()
示例#3
0
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()
示例#4
0
def chat_task(ctx, pipe, ncmds):
    n = Pyre(ctx)
    n.join("CHAT")
    n.start()

    # wait for someone else to join the chat
    while not n.get_peer_groups():
        pass

    pipe.send('ready'.encode('utf-8'))
    cmds = 0
    t0 = time.time()

    poller = zmq.Poller()
    poller.register(pipe, zmq.POLLIN)
    poller.register(n.inbox, zmq.POLLIN)
    while(True):
        items = dict(poller.poll())
        if pipe in items and items[pipe] == zmq.POLLIN:
            message = pipe.recv()
            # message to quit
            if message.decode('utf-8') == "$$STOP":
                break
            n.shout("CHAT", message)
        if n.inbox in items and items[n.inbox] == zmq.POLLIN:
            n.recv()
            cmds += 1
            if cmds == ncmds:
                msg = 'Got %s msgs in %0.2f sec' % (cmds, time.time() - t0)
                pipe.send(msg.encode('utf-8'))
    n.stop()
def run_time_sync_master(group):

    pts_group = group + '-time_sync-v1'
  
    # the time source in the example is python time.time you can change this.
    # replace with an implementation that give your custom time in floating sec.
    clock_service = Clock_Sync_Master(time)

    # This example is a clock service only, not a clock follower.
    # Therefore the rank is designed to always trump all others.
    rank = 1000
    discovery = Pyre('pupil-helper-service')
    discovery.join(pts_group)
    discovery.start()
    logger.info('Joining "{}" group with rank {}'.format(pts_group, rank))

    def announce_clock_service_info():
        discovery.shout(pts_group, [repr(rank).encode(), repr(clock_service.port).encode()])

    try:
        for event in discovery.events():
            if event.type == 'JOIN' and event.group == pts_group:
                logger.info('"{}" joined "{}" group. Announcing service.'.format(event.peer_name, pts_group))
                announce_clock_service_info()
    except KeyboardInterrupt:
        pass
    finally:
        logger.info('Leaving "{}" group'.format(pts_group))
        discovery.leave(pts_group)
        discovery.stop()
        clock_service.stop()
示例#6
0
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
示例#7
0
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()
示例#8
0
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()
示例#9
0
        def setup_group_member():
            group_member = Pyre(self.name)
            # set headers
            for header in self.default_headers:
                group_member.set_header(*header)
            # join active group
            group_member.join(self.active_group)

            # start group_member
            group_member.start()
            return group_member
    def network_thread(self, ctx, pipe):
        print("Network thread started..")
        n = Pyre(self.name)
        n.join("Car2X")
        n.start()

        poller = zmq.Poller()
        poller.register(pipe, zmq.POLLIN)
        poller.register(n.inbox, zmq.POLLIN)

        # wait for others
        while not n.peer_groups():
            time.sleep(0.0001)
            pass

        pipe.send('$$ready'.encode('utf-8'))

        while not self.stopped:
            items = dict(poller.poll())

            if pipe in items and items[pipe] == zmq.POLLIN:
                # handle outgoing messages
                try:
                    message = pipe.recv()
                    if message.decode('utf-8') == "$$STOP":
                        break
                    n.shouts("Car2X", message.decode('utf-8'))
                except zmq.error.Again:
                    print("ERROR! Again #1")
            if n.inbox in items and items[n.inbox] == zmq.POLLIN:
                try:
                    cmds = n.recv()

                    msg_type = cmds.pop(0)
                    msg_uuid = cmds.pop(0)
                    msg_name = cmds.pop(0)
                    if msg_type == "JOIN":
                        print("{} joined!".format(msg_name))
                        # ADD CAR IF NOT CONTROL
                        if msg_name[0:1] != "$":
                            self.window.hosts.append(msg_name)
                    elif msg_type == "EXIT":
                        print("{} left!".format(msg_name))
                        # REMOVE CAR
                        if msg_name in self.window.hosts:
                            self.window.hosts.remove(msg_name)
                    elif msg_type == "SHOUT":
                        # handling incoming information
                        msg_channel = cmds.pop(0)
                        msg_str = cmds.pop(0)
                        self.process_data(msg_str, msg_name)
                except zmq.error.Again:
                    print("ERROR! Again #2")
        n.stop()
示例#11
0
        def setup_group_member():
            group_member = Pyre(self.name)
            # set headers
            for header in self.default_headers:
                group_member.set_header(*header)
            # join active group
            group_member.join(self.active_group)

            # start group_member
            group_member.start()
            return group_member
示例#12
0
    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()
示例#13
0
    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()
示例#14
0
    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()
示例#16
0
    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()
示例#19
0
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()
示例#20
0
class Time_Sync(Plugin):
    """Synchronize time across local network.

    Implements the Pupil Time Sync protocol.
    Acts as clock service and as follower if required.
    See `time_sync_spec.md` for details.
    """
    icon_chr = chr(0xec15)
    icon_font = 'pupil_icons'

    def __init__(self, g_pool, node_name=None, sync_group_prefix='default', base_bias=1.):
        super().__init__(g_pool)
        self.sync_group_prefix = sync_group_prefix
        self.discovery = None

        self.leaderboard = []
        self.has_been_master = 0.
        self.has_been_synced = 0.
        self.tie_breaker = random.random()
        self.base_bias = base_bias

        self.master_service = Clock_Sync_Master(self.g_pool.get_timestamp)
        self.follower_service = None  # only set if there is a better server than us

        self.restart_discovery(node_name)

    @property
    def sync_group(self):
        return self.sync_group_prefix + '-time_sync-' + __protocol_version__

    @sync_group.setter
    def sync_group(self, full_name):
        self.sync_group_prefix = full_name.rsplit('-time_sync-' + __protocol_version__, maxsplit=1)[0]

    def init_ui(self):
        self.add_menu()
        self.menu.label = 'Network Time Sync'
        help_str = "Synchonize time of Pupil Captures across the local network."
        self.menu.append(ui.Info_Text('Protocol version: ' + __protocol_version__))

        self.menu.append(ui.Info_Text(help_str))
        help_str = "All pupil nodes of one group share a Master clock."
        self.menu.append(ui.Info_Text(help_str))
        self.menu.append(ui.Text_Input('node_name', self, label='Node Name', setter=self.restart_discovery))
        self.menu.append(ui.Text_Input('sync_group_prefix', self, label='Sync Group', setter=self.change_sync_group))

        def sync_status():
            if self.follower_service:
                return str(self.follower_service)
            else:
                return 'Clock Master'
        self.menu.append(ui.Text_Input('sync status', getter=sync_status, setter=lambda _: _, label='Status'))

        def set_bias(bias):
            if bias < 0:
                bias = 0.
            self.base_bias = bias
            self.announce_clock_master_info()
            self.evaluate_leaderboard()

        help_str = "The clock service with the highest bias becomes clock master."
        self.menu.append(ui.Info_Text(help_str))
        self.menu.append(ui.Text_Input('base_bias', self, label='Master Bias', setter=set_bias))
        self.menu.append(ui.Text_Input('leaderboard', self, label='Master Nodes in Group'))

    def recent_events(self, events):
        should_announce = False
        for evt in self.discovery.recent_events():
            if evt.type == 'SHOUT':
                try:
                    self.update_leaderboard(evt.peer_uuid, evt.peer_name, float(evt.msg[0]), int(evt.msg[1]))
                except Exception as e:
                    logger.debug('Garbage raised `{}` -- dropping.'.format(e))
                self.evaluate_leaderboard()
            elif evt.type == 'JOIN' and evt.group == self.sync_group:
                should_announce = True
            elif (evt.type == 'LEAVE' and evt.group == self.sync_group) or evt.type == 'EXIT':
                self.remove_from_leaderboard(evt.peer_uuid)
                self.evaluate_leaderboard()

        if should_announce:
            self.announce_clock_master_info()

        if not self.has_been_synced and self.follower_service and self.follower_service.in_sync:
            self.has_been_synced = 1.
            self.announce_clock_master_info()
            self.evaluate_leaderboard()

    def update_leaderboard(self, uuid, name, rank, port):
        for cs in self.leaderboard:
            if cs.uuid == uuid:
                if (cs.rank != rank) or (cs.port != port):
                    self.remove_from_leaderboard(cs.uuid)
                    break
                else:
                    # no changes. Just leave as is
                    return

        # clock service was not encountered before or has changed adding it to leaderboard
        cs = Clock_Service(uuid, name, rank, port)
        heappush(self.leaderboard, cs)
        logger.debug('{} added'.format(cs))

    def remove_from_leaderboard(self, uuid):
        for cs in self.leaderboard:
            if cs.uuid == uuid:
                self.leaderboard.remove(cs)
                logger.debug('{} removed'.format(cs))
                break

    def evaluate_leaderboard(self):
        if not self.leaderboard:
            logger.debug("nobody on the leader board.")
            return

        current_leader = self.leaderboard[0]
        if self.discovery.uuid() != current_leader.uuid:
            # we are not the leader!
            leader_ep = self.discovery.peer_address(current_leader.uuid)
            leader_addr = urlparse(leader_ep).netloc.split(':')[0]
            if self.follower_service is None:
                # make new follower
                self.follower_service = Clock_Sync_Follower(leader_addr,
                                                            port=current_leader.port,
                                                            interval=10,
                                                            time_fn=self.get_time,
                                                            jump_fn=self.jump_time,
                                                            slew_fn=self.slew_time)
            else:
                # update follower_service
                self.follower_service.host = leader_addr
                self.follower_service.port = current_leader.port
            return

        # we are the leader
        logger.debug("we are the leader")
        if self.follower_service is not None:
            self.follower_service.terminate()
            self.follower_service = None

        if not self.has_been_master:
            self.has_been_master = 1.
            logger.debug('Become clock master with rank {}'.format(self.rank))
            self.announce_clock_master_info()

    def announce_clock_master_info(self):
        self.discovery.shout(self.sync_group, [repr(self.rank).encode(),
                                               repr(self.master_service.port).encode()])
        self.update_leaderboard(self.discovery.uuid(), self.node_name, self.rank, self.master_service.port)

    @property
    def rank(self):
        return 4*self.base_bias + 2*self.has_been_master + self.has_been_synced + self.tie_breaker

    def get_time(self):
        return self.g_pool.get_timestamp()

    def slew_time(self, offset):
        self.g_pool.timebase.value += offset

    def jump_time(self, offset):
        ok_to_change = True
        for p in self.g_pool.plugins:
            if p.class_name == 'Recorder':
                if p.running:
                    ok_to_change = False
                    logger.error("Request to change timebase during recording ignored. Turn off recording first.")
                    break
        if ok_to_change:
            self.slew_time(offset)
            logger.info("Pupil Sync has adjusted the clock by {}s".format(offset))
            return True
        else:
            return False

    def restart_discovery(self, name):

        if self.discovery:
            if self.discovery.name() == name:
                return
            else:
                self.discovery.leave(self.sync_group)
                self.discovery.stop()
                self.leaderboard = []

        self.node_name = name or gethostname()
        self.discovery = Pyre(self.node_name)
        # Either joining network for the first time or rejoining the same group.
        self.discovery.join(self.sync_group)
        self.discovery.start()
        self.announce_clock_master_info()

    def change_sync_group(self, new_group_prefix):
        if new_group_prefix != self.sync_group_prefix:
            self.discovery.leave(self.sync_group)
            self.leaderboard = []
            if self.follower_service:
                self.follower_service.terminate()
                self.follower = None
            self.sync_group_prefix = new_group_prefix
            self.discovery.join(self.sync_group)
            self.announce_clock_master_info()

    def deinit_ui(self):
        self.remove_menu()

    def get_init_dict(self):
        return {'node_name': self.node_name,
                'sync_group_prefix': self.sync_group_prefix,
                'base_bias': self.base_bias}

    def cleanup(self):
        self.discovery.leave(self.sync_group)
        self.discovery.stop()
        self.master_service.stop()
        if self.follower_service:
            self.follower_service.stop()
        self.master_service = None
        self.follower_service = None
        self.discovery = None
def chat_task(ctx, pipe):
	print("Game started")
	print("Name: %s" %NAME)
	connected_players = 1
	network_players = 1
	leave_counter = 0

	#Set up node for the game
	n = Pyre("")
	n.set_header("header_name", NAME)

	#Join the group
	n.join(GROUPNAME)
	
	#Start broadcasting node
	n.start()

	# Set up poller
	poller = zmq.Poller()
	poller.register(pipe, zmq.POLLIN)  #Local pipe (contains commands/messages we send through terminal)
	poller.register(n.socket(), zmq.POLLIN)

	# A while loop constantly polls for new items = PULL system
	while True:

		#Wait for new message to be polled. This function blocks until there is a new message
		items = dict(poller.poll())

        	#This are messages from ourselves
		if pipe in items:
			message_pipe = pipe.recv()
			if message_pipe.decode('utf-8') == STOP_COMMAND:
				break
			#check if the message is a number
			elif message_pipe.decode('utf-8').isdigit() == True and yourturn == True:
				#variable to keep the loop going until a correct number is given
				status = True
				#check which symbol you got assigned
				if playerX == True:
					while status == True:
						number = int(message_pipe.decode('utf-8'))
						#check if the spot is free
						if board[number] != "X" and board[number] != "O":
							status = False
							yourturn = False
							print("New status board:")
							board[number] = "X"
							showboard()
							#check for a winning combination
							if checkall("X") == True:
								print("You win!")
								n.whisper(OPPONENT,str(number).encode('utf-8'))
								break
							#when there's no winning combination, it's the other player's turn
							else:
								print("Waiting for opponent's move...")
							#let your opponent know which number you chose
							n.whisper(OPPONENT,str(number).encode('utf-8'))
						else:
							print("Spot taken, try again")
							message_pipe = pipe.recv()
				else:
					while status == True:
						number = int(message_pipe.decode('utf-8'))
						if board[number] != "X" and board[number] != "O":
							status = False
							yourturn = False
							print("New status board:")
							board[number] = "O"
							showboard()
							if checkall("O") == True:
								print("You win!")
								n.whisper(OPPONENT,str(number).encode('utf-8'))
								break
							else:
								print("Waiting for opponent's move...")
							n.whisper(OPPONENT,str(number).encode('utf-8'))
						else:
							print("Spot taken, try again")
							message_pipe = pipe.recv()
			elif message_pipe.decode('utf-8').isdigit() == True and yourturn == False:
				print("It's not your turn, wait for your opponent's move")
			#if the message isn't a number, it is send as a message to your opponent
			else:
				print("Sending message to opponent: %s" %message_pipe.decode('utf-8'))
				n.whisper(OPPONENT,message_pipe)

		# Received messages from system or messages from other peers
		else:
			cmds = n.recv()
			#print(">>>>>>>RECEIVED MESSAGE: ", cmds)
			msg_type = cmds.pop(0)
			player_uuid = uuid.UUID(bytes=cmds.pop(0))
			#OPPONENT = player_uuid
			#print("player uuid: ", player_uuid)
			msg_name = cmds.pop(0)
			
			if msg_type.decode('utf-8') == "ENTER":
				headers = json.loads(cmds.pop(0).decode('utf-8'))
				network_players += 1
				if network_players == 2:
					print("--------------------------------------------------------------------------------")
					print("New player discovered in network")
					print("Name:", headers.get("header_name"))
					print("--------------------------------------------------------------------------------")
			elif msg_type.decode('utf-8') == "JOIN":
				connected_players += 1
				#check if there's stil room for a player
				if connected_players > 2:
					leave = "No free spot left"
					n.whisper(player_uuid, leave.encode('utf-8'))
				elif connected_players == 2:
					print("--------------------------------------------------------------------------------")
					print("%s joined group" %headers.get("header_name"), cmds.pop(0).decode('utf-8'))
					print("--------------------------------------------------------------------------------")
					#if there are 2 players, you know your opponent:
					OPPONENT = player_uuid
					showboard()
					#randomly choose if you want to start
					assign = random.randint(0,1)
					if assign == 1:
						player_start = True
						n.whisper(OPPONENT, "$$Istart".encode('utf-8'))
					else:
						player_start = False
						n.whisper(OPPONENT, "$$Ustart".encode('utf-8'))						
			elif msg_type.decode('utf-8') == "WHISPER":
				message_opponent = cmds.pop(0).decode('utf-8')
				if message_opponent == "No free spot left":
					leave_counter += 1
					#if you get the message that you must leave from 2 other players, you are the third player
					if leave_counter == 2:
						print(message_opponent)
						break
				#if the random generators both got a compatible result, the game can start
				elif message_opponent == "$$Istart" and player_start == False:
					playerX = False
					yourturn = False
					print("You are symbol O")
					print("You opponent may start, please wait...")
				elif message_opponent == "$$Ustart" and player_start == True:
					playerX = True
					yourturn = True
					print("You are symbol X")
					print("You may start")
					print("Where do you want to place your X?")
				#when the results are incompatible: try again
				elif message_opponent == "$$Istart" and player_start == True:
					assign = random.randint(0,1)
					if assign == 1:
						player_start = True
						n.whisper(OPPONENT, "$$Istart".encode('utf-8'))
					else:
						player_start = False
						n.whisper(OPPONENT, "$$Ustart".encode('utf-8'))
				elif message_opponent == "$$Ustart" and player_start == False:
					assign = random.randint(0,1)
					if assign == 1:
						player_start = True
						n.whisper(OPPONENT, "$$Istart".encode('utf-8'))
					else:
						player_start = False
						n.whisper(OPPONENT, "$$Ustart".encode('utf-8'))
				#if you receive a number, this is your opponent's move
				elif message_opponent.isdigit() == True:
					yourturn = True
					print("--------------------------------------------------------------------------------")
					print("Number opponent: ",message_opponent)
					print("New status board:")
					#check for a winning combination based on which player you are
					if playerX == True:
						board[int(message_opponent)] = "O"
						showboard()
						if checkall('O') == True:
							print("You loose!")
							break
						#if your opponent didn't make a winning combination, it's your turn
						else:
							print("Your turn")
							print("Where do you want to place your X?")
					else:
						board[int(message_opponent)] = "X"
						showboard()
						if checkall('X') == True:
							print("You loose!")
							break
						else:
							print("Your turn")
							print("Where do you want to place your O?")					
				#if you just received a message, print it
				else:
					print("Opponent says: ",message_opponent)


			elif msg_type.decode('utf-8') == "EXIT":
				if connected_players == 2:
					print("%s left network" %headers.get("header_name"))
					connected_players -= 1
					print("Total connected players: ", connected_players)
				leave_counter -= 1
	print("Game stopped")
	n.stop()
示例#22
0
    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()
示例#23
0
    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()
示例#24
0
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])
示例#25
0
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
示例#26
0
class Bridge(object):
    """docstring for Bridge"""
    def __init__(self, uvc_id):
        super(Bridge, self).__init__()

        self.data_seq = 0
        self.note_seq = 0

        # init capture
        self.cap = uvc.Capture(uvc_id)
        logger.info('Initialised uvc device {}'.format(self.cap.name))

        # init pyre
        self.network = Pyre(socket.gethostname()+self.cap.name[-4:])
        self.network.join(GROUP)
        self.network.start()
        logger.info('Bridging under "{}"'.format(self.network.name()))

        # init sensor sockets
        ctx = zmq.Context()
        generic_url = 'tcp://*:*'
        public_ep = self.network.endpoint()
        self.note, self.note_url = self.bind(ctx, zmq.PUB, generic_url, public_ep)
        self.data, self.data_url = self.bind(ctx, zmq.PUB, generic_url, public_ep, set_hwm=1)
        self.cmd, self.cmd_url = self.bind(ctx, zmq.PULL, generic_url, public_ep)

    def loop(self):
        logger.info('Entering bridging loop...')
        self.network.shout(GROUP, self.sensor_attach_json().encode())
        try:
            while True:
                self.poll_network()
                self.poll_cmd_socket()
                self.publish_frame()

        except KeyboardInterrupt:
            pass
        except Exception:
            import traceback
            traceback.print_exc()
        finally:
            self.network.shout(GROUP, json.dumps({
                'subject': 'detach',
                'sensor_uuid': self.network.uuid().hex
            }).encode())
            logger.info('Leaving bridging loop...')

    def publish_frame(self):
        frame = self.cap.get_frame_robust()
        now = time.time()
        index = self.data_seq
        self.data_seq += 1
        self.data_seq %= sequence_limit

        jpeg_buffer = frame.jpeg_buffer
        m = hashlib.md5(jpeg_buffer)
        lower_end = int(m.hexdigest(), 16) % 0x100000000
        meta_data = struct.pack('<LLLLdLL', 0x10, frame.width, frame.height, index, now, jpeg_buffer.size, lower_end)
        self.data.send_multipart([self.network.uuid().hex.encode(), meta_data, jpeg_buffer])

    def poll_network(self):
        for event in self.network.recent_events():
            if event.type == 'JOIN' and event.group == GROUP:
                self.network.whisper(event.peer_uuid, self.sensor_attach_json().encode())

    def poll_cmd_socket(self):
        while has_data(self.cmd):
            sensor, cmd_str = self.cmd.recv_multipart()
            try:
                cmd = json.loads(cmd_str.decode())
            except Exception as e:
                logger.debug('Could not parse received cmd: {}'.format(cmd_str))
            else:
                logger.debug('Received cmd: {}'.format(cmd))
                if cmd.get('action') == 'refresh_controls':
                    self.publish_controls()
                elif cmd.get('action') == 'set_control_value':
                    val = cmd.get('value', 0)
                    if cmd.get('control_id') == 'CAM_RATE':
                        self.cap.frame_rate = self.cap.frame_rates[val]
                    elif cmd.get('control_id') == 'CAM_RES':
                        self.cap.frame_size = self.cap.frame_sizes[val]
                    self.publish_controls()

    def __del__(self):
        self.note.close()
        self.data.close()
        self.cmd.close()
        self.network.stop()

    def publish_controls(self):
        self.note.send_multipart([
            self.network.uuid().hex.encode(),
            self.frame_size_control_json().encode()])
        self.note.send_multipart([
            self.network.uuid().hex.encode(),
            self.frame_rate_control_json().encode()])

    def sensor_attach_json(self):
        sensor = {
            "subject": "attach",
            "sensor_name": self.cap.name,
            "sensor_uuid": self.network.uuid().hex,
            "sensor_type": 'video',
            "notify_endpoint": self.note_url,
            "command_endpoint": self.cmd_url,
            "data_endpoint": self.data_url
        }
        return json.dumps(sensor)

    def frame_size_control_json(self):
        index = self.note_seq
        self.note_seq += 1
        self.note_seq %= sequence_limit
        curr_fs = self.cap.frame_sizes.index(self.cap.frame_size)
        return json.dumps({
            "subject": "update",
            "control_id": "CAM_RES",
            "seq": index,
            "changes": {
                "value": curr_fs,
                "dtype": 'intmapping',
                "min": None,
                "max": None,
                "res": None,
                "def": 0,
                "caption": 'Resolution',
                "readonly": False,
                "map": [{
                    'value': idx,
                    'caption': '{:d}x{:d}'.format(*fs)
                } for idx, fs in enumerate(self.cap.frame_sizes)]
            }
        })

    def frame_rate_control_json(self):
        index = self.note_seq
        self.note_seq += 1
        self.note_seq %= sequence_limit
        curr_fr = self.cap.frame_rates.index(self.cap.frame_rate)
        return json.dumps({
            "subject": "update",
            "control_id": "CAM_RATE",
            "seq": index,
            "changes": {
                "value": curr_fr,
                "dtype": 'intmapping',
                "min": None,
                "max": None,
                "res": None,
                "def": 0,
                "caption": 'Frame Rate',
                "readonly": False,
                "map": [{
                    'value': idx,
                    'caption': '{:.1f} Hz'.format(fr)
                } for idx, fr in enumerate(self.cap.frame_rates)]
            }
        })

    def bind(self, ctx, sock_type, url, public_ep, set_hwm=None):
        sock = ctx.socket(sock_type)
        if set_hwm:
            sock.set_hwm(set_hwm)
        sock.bind(url)
        ep = sock.last_endpoint.decode()
        port = ep.split(':')[-1]
        public_ep.split(':')[-1]
        public_addr = public_ep.split(':')[:-1]
        return sock, ':'.join(public_addr+[port])
def run_time_sync_follower(time_fn, jump_fn, slew_fn, group):
    """Main follower logic"""

    # Start Pyre node and find clock services in `pts_group`
    pts_group = group + '-time_sync-v1'
    discovery = Pyre('pupil-helper-follower')
    discovery.join(pts_group)
    discovery.start()
    logger.info('Joining "{}" group'.format(pts_group))

    # The leaderboard keeps track of all clock services
    # and is used to determine the clock master
    leaderboard = []
    follower_service = None

    def update_leaderboard(uuid, name, rank, port):
        """Add or update an existing clock service on the leaderboard"""
        for cs in leaderboard:
            if cs.uuid == uuid:
                if (cs.rank != rank) or (cs.port != port):
                    remove_from_leaderboard(cs.uuid)
                    break
                else:
                    # no changes. Just leave as is
                    return

        # clock service was not encountered before or has changed adding it to leaderboard
        cs = Clock_Service(uuid, name, rank, port)
        heappush(leaderboard, cs)
        logger.debug('<{}> added'.format(cs))

    def remove_from_leaderboard(uuid):
        """Remove an existing clock service from the leaderboard"""
        for cs in leaderboard:
            if cs.uuid == uuid:
                leaderboard.remove(cs)
                logger.debug('<{}> removed'.format(cs))
                break

    def evaluate_leaderboard(follower_service):
        """
        Starts/changes/stops the time follower service according to
        who the current clock master is.
        """
        if not leaderboard:
            logger.debug("nobody on the leader board.")
            if follower_service is not None:
                follower_service.terminate()
            return None

        current_leader = leaderboard[0]
        leader_ep = discovery.peer_address(current_leader.uuid)
        leader_addr = urlparse(leader_ep).netloc.split(':')[0]
        logger.info('Following <{}>'.format(current_leader))
        if follower_service is None:
            # make new follower
            follower_service = Clock_Sync_Follower(leader_addr,
                                                   port=current_leader.port,
                                                   interval=10,
                                                   time_fn=time_fn,
                                                   jump_fn=jump_fn,
                                                   slew_fn=slew_fn)
        else:
            # update follower_service
            follower_service.host = leader_addr
            follower_service.port = current_leader.port

        return follower_service

    try:
        # wait for the next Pyre event
        for event in discovery.events():
            if event.type == 'SHOUT':
                # clock service announcement
                # ill-formatted messages will be dropped
                try:
                    update_leaderboard(event.peer_uuid,
                                       event.peer_name,
                                       float(event.msg[0]),
                                       int(event.msg[1]))
                except Exception as e:
                    logger.debug('Garbage raised `{}` -- dropping.'.format(e))
                follower_service = evaluate_leaderboard(follower_service)
            elif ((event.type == 'LEAVE' and event.group == pts_group)
                    or event.type == 'EXIT'):
                remove_from_leaderboard(event.peer_uuid)
                follower_service = evaluate_leaderboard(follower_service)

    except KeyboardInterrupt:
        pass
    finally:
        discovery.leave(pts_group)
        discovery.stop()
        if follower_service is not None:
            follower_service.terminate()
示例#28
0
class Discovery:

    def __init__(self, my_name, my_ip, group_name):

        self.name = my_name
        self.ip = my_ip
        self.group = group_name

        # node dict is of the format ip: name
        # This is because a user (name) may move to a new ip.
        # Duplicate ip's are not allowed, but more than 1 ip may share the 
        # same name. This is because a user may log in to multiple devices.
        # 
 
        self.node_dict = {}

        self.node = Pyre(self.group)
        self.node.set_header(self.name, self.ip)
        self.node.join(self.group)
        self.node.start()

        # this runs forever for testing, but should be run as a thread
        self._node_update_task()

    """ This task will keep the node dictionary updated.

        The node will periodically send an update (heartbeat) control message
        which has the name and ip as in the header.

        Periodically recieve the incomming messages and update the ip name dictionary
    """
    def _node_update_task(self):
        while True:
            cmds = self.node.recv()
            msg_type = cmds.pop(0)

            # debug prints
            print("NODE_MSG TYPE: %s" % msg_type)
            print("NODE_MSG PEER: %s" % uuid.UUID(bytes=cmds.pop(0)))
            print("NODE_MSG NAME: %s" % cmds.pop(0))

            # headers are packed json
            if msg_type.decode('utf-8') == "SHOUT":
                print("NODE_MSG GROUP: %s" % cmds.pop(0))
            elif msg_type.decode('utf-8') == "ENTER":
                headers = json.loads(cmds.pop(0).decode('utf-8'))
                print("NODE_MSG HEADERS: %s" % headers)
                for key in headers:
                    print("key = {0}, value = {1}".format(key, headers[key]))
            print("NODE_MSG CONT: %s" % cmds)


    """
     Get the currwnt nodes dict
     ip, name, group
    """
    def get_active_nodes(self):

        # return the active nodes dictionary
        return self.node_dict

    def get_idle_nodes(self):
        return self.node_dict
示例#29
0
Contact information: [email protected]
'''

import pyre
from pyre import Pyre

from pyre import zhelper
import zmq
import uuid
import logging
import sys
import json

n = Pyre("receiver_node")
print('Join group [CHAT]')
n.join("CHAT")

print('node START')
n.start()

msg_data = {
    "header": {
        "type": "CMD",
        "version": "0.1.0",
        "metamodel": "ropod-msg-schema.json",
        "msg_id": "0d05d0bc-f1d2-4355-bd88-edf44e2475c8",
        "timestamp": "2017-11-11T11:11:00Z"
    },
    "payload": {
        "metamodel": "ropod-demo-cmd-schema.json",
        "answerList": [{
示例#30
0
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()
示例#31
0
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
示例#32
0
文件: network.py 项目: vedb/pyndsi
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]
示例#33
0
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
示例#34
0
    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()
示例#35
0
    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()
示例#36
0
    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()
示例#37
0
    def thread_loop(self, context, pipe):
        n = Pyre(self.name)
        n.join(self.group)
        n.start()

        poller = zmq.Poller()
        poller.register(pipe, zmq.POLLIN)
        logger.debug(n.socket())
        poller.register(n.socket(), zmq.POLLIN)
        while (True):
            try:
                #this should not fail but it does sometimes. We need to clean this out.
                # I think we are not treating sockets correclty as they are not thread-save.
                items = dict(poller.poll())
            except zmq.ZMQError:
                logger.warning('Socket fail.')
            # print(n.socket(), items)
            if pipe in items and items[pipe] == zmq.POLLIN:
                message = pipe.recv()
                # message to quit
                if message.decode('utf-8') == "EXIT_THREAD":
                    break
                logger.debug("Emitting to '%s' to '%s' " %
                             (message, self.group))
                n.shouts(self.group, message)
            if n.socket() in items and items[n.socket()] == zmq.POLLIN:
                cmds = n.recv()
                msg_type = cmds.pop(0)
                msg_type = msg_type.decode('utf-8')
                if msg_type == "SHOUT":
                    uid, name, group, msg = cmds
                    logger.debug("'%s' shouts '%s'." % (name, msg))
                    if start_rec in msg:
                        session_name = msg.replace(start_rec, '')
                        self.notify_all({
                            'name': 'rec_should_start',
                            'session_name': session_name,
                            'network_propagate': False
                        })
                    elif stop_rec in msg:
                        self.notify_all({
                            'name': 'rec_should_stop',
                            'network_propagate': False
                        })
                    elif sync_time in msg:
                        offset = float(msg.replace(sync_time, ''))
                        if self.ok_to_set_timebase():
                            self.adjust_timebase(offset)

                elif msg_type == "ENTER":
                    uid, name, headers, ip = cmds
                elif msg_type == "JOIN":
                    uid, name, group = cmds
                    if group == self.group:
                        self.group_members[uid] = name
                        self.update_gui()
                elif msg_type == "EXIT":
                    uid, name = cmds
                    try:
                        del self.group_members[uid]
                    except KeyError:
                        pass
                    else:
                        self.update_gui()
                elif msg_type == "LEAVE":
                    uid, name, group = cmds
                elif msg_tpye == "WHISPER":
                    pass

        logger.debug('thread_loop closing.')
        self.thread_pipe = None
        n.stop()
class Transport():
    '''Message transport mechanisms for LCAS'''

    def send(self, dest, ntuple):
        '''Send given ntuple to Transport named dest. If dest isn't listening for messages from this Transport, the message will (currently) be silently ignored.'''
        if self._prefix is not None:
            dest = self._prefix + dest
        self._pyre.shout(dest, json.dumps(ntuple).encode('utf-8'))
    # send()

    # Notes on subscribe
    #
    # The callback is called in the same thread that listens for pyre
    # messages, so the callback should start a new thread if it's
    # going to block or take a long time to run.
    #
    # The callback must take one positional argument, the tuple, and
    # can OPTIONALLY take a keyword argument (e.g. **kw). I use the
    # inspect module to detect this. May be too clever for my own
    # good.
    #
    # There can be only one callback for a given remote. If you call
    # subscribe again with the same remote, it raises an error.

    def subscribe(self, remote, callback):
        '''When a message is sent from a Transport named remote to this transport, call the passed callback with the ntuple as the first argument. If the callback takes **kw, it will also pass additional metadata such as the Transport name, UUID, and IP of the sender.'''
        if self._prefix is not None:
            remote = self._prefix + remote
        if remote in self._subscribers:
            raise TransportError(self, 'Transport.subscribe() was called a second time with the same remote (\"%s\"). You must call Transport.unsubscribe() before setting a new callback.'%(remote))
        self._subscribers[remote] = callback
    # subscribe()

    def unsubscribe(self, remote):
        '''Stop listening for messages from remote.'''
        if self._prefix is not None:
            remote = self._prefix + remote
        if remote in self._subscribers:
            del self._subscribers[remote]
    # unsubscribe()

    def subscribe_all(self, callback):
        '''Call callback every time a message is sent from any remote Transport to this Transport.'''
        if self._subscribe_all is not None:
            raise TransportError(self, 'Transport.subscribe_all() was called a second time. You must call Transport.unsubscribe_all() before setting a new callback.')
        self._subscribe_all = callback
    # subscribe_all()

    def unsubscribe_all(self):
        self._subscribe_all = None
    # unsubscribe_all()

    # Notes on get()
    #    
    # If you already subscribe to remote, temporarly overrides
    # the subscribe. The subscribed callback will NOT be called.
    # The subscription is replaced after get() returns.

    def get(self, remote):
        '''Block waiting for a message from a Transport named remote. Returns python namedtuple containing fields object, uuid, name, ip, datetime.'''

        if self._prefix is not None:
            remote = self._prefix + remote

        # The final python namedtuple to be returned needs to be shared
        # between get_callback() and get(). In python3, you can use
        # nonlocal, but in python2 you need a trick (storing in a
        # data structure). The actual value to be returned will
        # be ret[0].
        ret = [ None ]

        # The event e will get set when a message is read by the
        # readthread.
        e = threading.Event()

        # This function is a callback used to detect the next message.
        # It stores the message in a Python namedtuple and sets the
        # event.

        def get_callback(tup, **kw):
            ret[0] = collections.namedtuple('TransportEnvelope', ['object', 'uuid', 'name', 'ip', 'datetime'])(tup, kw['uuid'], kw['name'], kw['ip'], kw['datetime'])
            # Inform get() that ret is ready to be returned.
            e.set()
        # get_callback()

        # Store the old callback, if any
        oldcb = self._subscribers.get(remote, None)

        # Set the subscription
        self._subscribers[remote] = get_callback
        
        # Wait for the callback to be called.
        e.wait()

        # Restore the old subscription, if any.
        if oldcb is not None:
            self._subscribers[remote] = oldcb
        else:
            del self._subscribers[remote]

        # Return the namedtuple.
        return ret[0]
    # get()

    def quit_federation(self):
        '''Send a quit message to all agents in this federation, and then close down the Transport.'''
        if self._run:
            self._pyre.shouts(self._globalchannel, u"QUIT")
            self._run = False
            # Wait for the readthread to finish
            self._readthread.join()
            # Tell Pyre to shut down
            self._pyre.stop()

    def is_running(self):
        '''Return the status of this Transport. If the Transport isn't running, you should not send it messages and the callbacks will not be called.'''
        return self._run

    ######################################################################
    # All private methods below here

    def __init__(self, myname, port=None, prefix=None):
        # NOTE: Seems to be a bug in Pyre where you can't set the port.
        if port is not None:
            raise NotImplementedError('There is a bug in Pyre that prevents setting of the discovery port. If you require multiple federations of Pyre components, use prefix instead of port in Transport constructor.')

        # dict of remote name to callback. See subscribe method above.
        self._subscribers = {}
        
        # Callback for all message (or None if none registered)
        self._subscribe_all = None

        self._prefix = prefix

        # Attach the federation name as a prefix to both this channel
        # and the global channel. The global channel is currently
        # just used for QUIT messages.

        if prefix is not None:
            myname = prefix + myname
            self._globalchannel = prefix + "GLOBAL"
        else:
            self._globalchannel = "GLOBAL"

        self._pyre = Pyre(myname)
        if port is not None:
            self._pyre.set_port(port)

        self._pyre.join(myname)
        self._pyre.join(self._globalchannel)
        self._pyre.start()

        # Dict of (UUIDs => IP addresses) that have sent a valid ENTER message
        self._uuid2ip = {}

        self._run = True

        self._readthread = threading.Thread(target=self._readworker)
        self._readthread.start()
    # __init__()

    # Handle pyre messages. Run in self._readthread
    def _readworker(self):
        '''This method is called in a separate thread to handle messages sent over pyre. It dispataches to methods named for the pyre events (e.g. _ENTER).'''

        # Set up a poller so recv doesn't block. Possibly not needed
        # since we'll always get an event when the other agents quit,
        # but just in case something goes wrong, we want to be sure to
        # close down.

        poller = zmq.Poller()
        sock = self._pyre.socket()
        poller.register(sock, zmq.POLLIN)

        while self._run:
            # Wait until a message is received OR one second timeout.
            items = dict(poller.poll(1000))
            if not (sock in items and items[sock] == zmq.POLLIN):
                # This should only happen if we time out.
                continue
            # There's an event waiting. Read and process it.
            event = self._pyre.recv()
            logger.debug('Transport %s-%s received event %s'%(self._pyre.uuid(), self._pyre.name(), event))
            eventtype = event[0].decode('utf-8')
            # Sender's uuid and name
            sid = uuid.UUID(bytes=event[1])
            name = event[2].decode('utf-8')
            # Make sure we've seen matching ENTER for all events
            if eventtype != 'ENTER' and sid not in self._uuid2ip:
                raise TransportProtocolError(self, 'Received event %s with no matching ENTER.'%(event))
                continue

            if eventtype == 'ENTER':
                # Changed
                url = event[4].decode('utf-8')
                self._ENTER(sid, name, url)
            elif eventtype == 'JOIN':
                channel = event[3].decode('utf-8')
                self._JOIN(sid, name, channel)
            elif eventtype == 'SHOUT':
                channel = event[3].decode('utf-8')
                message = event[4].decode('utf-8')
                if channel == self._globalchannel and message == "QUIT":
                    # Set ourself to stop running, close down pyre, exit
                    # worker thread.
                    self._run = False
                    self._pyre.stop()
                    break
                else:
                    self._SHOUT(sid, name, channel, message)
            elif eventtype == 'WHISPER':
                message = event[3].decode('utf-8')
                self._WHISPER(sid, name, message)
            elif eventtype == 'LEAVE':
                channel = event[3].decode('utf-8')
                self._LEAVE(sid, name, channel)
            elif eventtype == 'EXIT':
                self._EXIT(sid, name)
            else:
                raise TransportProtocolError(self, 'Illegal event type in event %s'%(event))
    # _readworker()

    # The following methods are named for the pyre event that this
    # instance has received. They are called automatically from the
    # worker thread that's listening for events.

    def _ENTER(self, sid, name, url):
        # We expect all connections to be tcp on some port. This regular
        # expression is used to extract the ip part.
        urlmatch = re.match('tcp://([0-9.]+):[0-9]+$', url)
        if urlmatch:
            ip = urlmatch.group(1)
            if is_valid_ip(ip):
                # Everything looks good. Add to list of valid uuids.
                self._uuid2ip[sid] = ip
            else:
                raise TransportSecurityError(self, 'Message from invalid IP address %s in ENTER %s %s %s. Check the function is_valid_ip() in Transport.py.'%(ip, sid, name, url))
        else:
            raise TransportProtocolError(self, 'Malformed URL in ENTER %s %s %s'%(sid, name, url))
    # _ENTER()

    def _JOIN(self, sid, name, channel):
        pass
    # _JOIN()

    def _SHOUT(self, sid, name, channel, message):
        now = datetime.datetime.now()
        logger.debug('In _SHOUT with %s %s %s %s'%(sid, name, channel, message)) #???
        if name in self._subscribers:
            logger.debug('got a subscription')
            cb = self._subscribers[name]
            self._call_callback(cb, sid, name, channel, message, now)
        if self._subscribe_all is not None:
            cb = self._subscribe_all
            self._call_callback(cb, sid, name, channel, message, now)
    # _SHOUT()

    def _call_callback(self, cb, sid, name, channel, message, now):
        if inspect.getargspec(cb).keywords is None:
            cb(json.loads(message))
        else:
            cb(message, uuid=sid, name=name, ip=self._uuid2ip[sid], datetime=now)
    # _call_callback


    def _WHISPER(self, sid, name, message):
        raise TransportProtocolError(self, 'Unexpected WHISPER from %s %s'%(sid, name))
    # _WHISPER()

    def _LEAVE(self, sid, name, channel):
        pass
    # _LEAVE()

    def _EXIT(self, sid, name):
        # Remove sid from list of valid uuids. This should
        # never be an error since we check in _readworker().
        del self._uuid2ip[sid]
示例#39
0
def chat_task(ctx,pipe):
	print("communication started")

	GROUPNAME = "Quizzzzz"
	StopCmnd = "$$quit"
	OPPONENT = "opponent"
	
	print("name: %s" %NAME)
	
	connected_players = 1
	
	# set up node for the user
	n = Pyre(GROUPNAME)
	n.set_header('Name', NAME)
	
	# join the groupchat
	n.join(GROUPNAME)
	#print("UUID %s" %n.uuid())
	 
				
	# start broadcasting signal 
	n.start()

	# set up poller
	poller = zmq.Poller()
	poller.register(pipe,zmq.POLLIN)
	poller.register(n.socket(),zmq.POLLIN)

	# looping constantly to recieve messages
	while True:
		items = dict(poller.poll())
		
		if pipe in items:
			message = pipe.recv()
			if message.decode('utf-8') == StopCmnd:
				break
			# uppercase letters for question to whole group
			elif message.decode('utf-8').isupper() == True: 
				print("Question is: %s" %message)
				n.shouts(GROUPNAME,"Question to group is: %s" %message.decode('utf-8'))
				answer = 0
			# lowercase to last person who asked question in the group
			elif message.decode('utf-8').islower()  == True:
				message = NAME + "'s answer is=" + message
				n.whisper(PEER,message)
			else:
				print("please don't mix up or lowercase or use not only numbers")
	
		else:
			msgrecv = n.recv()
			#print(msgrecv)
			msg_type = msgrecv.pop(0)
			msg_sender = uuid.UUID(bytes=msgrecv.pop(0))
			PEER = msg_sender
			msg_name = msgrecv.pop(0)

			if msg_type.decode('utf-8') == "ENTER":
				headers = json.loads(msgrecv.pop(0).decode('utf-8'))
				print("New player discovered in network")
				print("New player = %s " %headers.get("Name"))
			elif msg_type.decode('utf-8') == "JOIN":
				print("New player has joined the group")
				print("New player = %s" %headers.get("Name"))
				connected_players += 1
				print("#players = %s" %connected_players)
			elif msg_type.decode('utf-8') == "SHOUT":
				print(msgrecv.pop(1))
			elif msg_type.decode('utf-8') == "WHISPER":
				if msgrecv[0] == "You have to ask next question":
					print("You have to ask next question")
					n.shout(GROUPNAME, "%s is new quizmaster" %NAME)
					answer = 0
				else:
					print(msgrecv.pop(0))
					answer +=1
					if answer == connected_players -1: #choosing new quizmaster randomly
						players = n.peers()
						next_master = players.pop(random.randint(0,connected_players-2))
						n.whisper(next_master,"You have to ask next question")
			
	
	print("Left current game")	
	n.stop()
class ZyreToZMQModule:
    """ The ZyreToZMQModule Base Class """
   
    
    def __init__(self,ctx = None,name = "Default",headers=None,groups=None,config_file=None,polling_timeout = 1,sim_time=2):

        self.logger = logging.getLogger(name)
        self.logger.setLevel(logging.DEBUG)
        # create the console output logging
        sh = logging.StreamHandler()
        sh.setLevel(logging.INFO)
        # create a logger writing into a log file
        fh = logging.FileHandler(name + ".log")
        fh.setLevel(logging.DEBUG)
        # create formatter and add it to the handlers
        # see https://docs.python.org/2/library/logging.html#logrecord-attributes for what can be logged
        fh.setFormatter(logging.Formatter('Name: %(name)s, ProcessName: %(processName)s, ThreadName: %(threadName)s, Module: %(module)s, FunctionName: %(funcName)s, LineNo: %(lineno)d, Level: %(levelname)s, Msg: %(message)s'))
        #sh.setFormatter(logging.Formatter('Module: %(module)s, FunctionName: %(funcName)s, LineNo: %(lineno)d, Level: %(levelname)s, Msg: %(message)s'))
        sh.setFormatter(logging.Formatter('Name: %(name)s, %(module)s/%(funcName)s[%(levelname)s]: %(message)s (lineno:%(lineno)d)'))
        # add the handlers to logger
        self.logger.addHandler(sh)
        self.logger.addHandler(fh)
        self.logger.propagate = False # don't pass messages to parent loggers

        if not type(ctx) ==  zmq.sugar.context.Context:
            self.logger.warn("Created ZMQ context. Please supply a ZMQ context next time.")
            ctx = zmq.Context()
        self.ctx = ctx
        if not type(name) == str:
            name = "Default"
            self.logger.warn("Please provide a the name as a string. Setting name to default: %s." % name)
        self.name = name
        if not headers:
            self.logger.warn("Please provide a model and other header information.")
            headers = {}
        self.headers = headers
        if not groups:
            groups = ["SHERPA"]
            self.logger.warn("Please provide a list with group names to which it will listen. Will set it to default: %s" %groups)
        self.groups = groups
        if not config_file:
            # will be opened during configuration
            self.logger.error("No config file provided for initial configuration")
            exit()
      
        self.config_file = config_file
        self.config = None
        self.alive = True # used for exiting once the node is stopped
        self.line_controller = None # stores uid of line controller this module is listening to (to avoid several line controllers)
        self.com_timeout = polling_timeout # time_out in msec after which poller returns
        self.sim_time = sim_time # time in msec
        self.inbox = []
        self.outbox = []
             
        # Node setup
        self.node = Pyre(self.name)
        for key in self.headers:
            self.node.set_header(key,self.headers[key])
        for group in self.groups:
            self.node.join(group)
        #self.node.set_verbose()
        self.node.start()
        
        # Socket setup
        self.poller = zmq.Poller()
        self.poller.register(self.node.socket(), zmq.POLLIN)

        port = "12911" 
        self.zmq_socket = self.ctx.socket(zmq.PUB)
        self.zmq_socket.bind("tcp://*:%s" % port)
   

        self.run()


    def run(self):
        """ Running loop of this process:
        [COMMUNICATION]     Check communication channels and parse all messages.
        """
        while self.alive:
            try:
                #[COMMUNICATION]
                self.communication()
                #[LOGGING]
                #self.logging()
                time.sleep(1)
            except (KeyboardInterrupt, SystemExit):
                break
        self.node.stop()


    def communication(self):
        """ This function handles the communication """

        # Check if communication is ready
        if not self.poller:
            self.logger.warn("No communication channels yet.")
        # Process input
        items = dict(self.poller.poll(self.com_timeout))
        # Get input from Pyre socket and put it in inbox which is processed in the following steps
        #logger.debug("Start processing incoming messages")
        if self.node.socket() in items and items[self.node.socket()] == zmq.POLLIN: 
            self.logger.info("Received %d msgs." % len(items))
            #print "msg arrived. inbox len %d" % len(self.inbox)
            msg_frame = self.node.recv()
            msg_type = msg_frame.pop(0)
            peer_uid = uuid.UUID(bytes=msg_frame.pop(0))
            peer_name = msg_frame.pop(0)   
            self.logger.info("Msg type: %s" % msg_type)         
            self.logger.info("Sender: %s" % peer_name)   
            # For shout and whisper take message payload and put it into inbox assuming it is correct
            # For the other zyre msgs create a JSON obj and put that into inbox
            # TODO: add validation
            if msg_type == "SHOUT":
                group = msg_frame.pop(0)
                msg = json.loads(msg_frame.pop(0))
                msg["sender_UUID"] = peer_uid
                msg["sender_name"] = peer_name
#                self.inbox.append(msg)
                self.outbox.append(msg)
            elif msg_type == "WHISPER":
                msg = json.loads(msg_frame.pop(0))
                msg["sender_UUID"] = peer_uid
                msg["sender_name"] = peer_name
                self.inbox.append(msg)        
            # don't care about join and leave messages; if necessary, split to have separate events               
#             elif msg_type == "LEAVE" or msg_type == "JOIN":
#                 group = msg_frame.pop(0)
#                 event = json.dumps({"metamodel": "http://www.sherpa-project.eu/examples/sherpa_msgs",
#                                     "model": "http://www.sherpa-project.eu/examples/sherpa_msgs/zyre_events",
#                                     "type": "leave/join",
#                                     "sender_UUID": peer_uid,
#                                     "sender_name": peer_name,
#                                     "payload": {}
#                                     })
#                 self.inbox.append(event)
            elif msg_type == "ENTER":
                headers = json.loads(msg_frame.pop(0))
                event = {"metamodel": "http://www.sherpa-project.eu/examples/sherpa_msgs",
                         "model": "http://www.sherpa-project.eu/examples/sherpa_msgs/zyre_events",
                         "type": "enter",
                         "sender_UUID": peer_uid,
                         "sender_name": peer_name,
                         "payload": {"header": headers}
                         }
                self.inbox.append(event)
            elif msg_type == "EXIT":
                event = {"metamodel": "http://www.sherpa-project.eu/examples/sherpa_msgs",
                         "model": "http://www.sherpa-project.eu/examples/sherpa_msgs/zyre_events",
                         "type": "exit",
                         "sender_UUID": peer_uid,
                         "sender_name": peer_name,
                         "payload": {}
                         }
                self.inbox.append(event)
        # Process output and send all msgs there until it is empty, but only if a line controller is connected.
        if self.outbox: #only do if there really is something in the outbox
            #if self.lcsm.sm.curr_state._name == "Idle" or self.lcsm.sm.curr_state._name == "Busy":
            if true:
                self.logger.info("Start processing messages in outbox. Number of msgs in outbox: %d" % len(self.outbox))
                while self.outbox:
                    # since we assume all msgs conform to the sherpa_msgs JSON model, simply shout them out
                    # TODO: add validation
                    msg = self.outbox.pop()
                    if type(msg) == dict:
                        self.logger.info("outbox msg type: " + msg["type"])
                        self.node.shout("SHERPA", json.dumps(msg))
                        
                        #WM message
                        
                        msg_wm_update = {
                          "@worldmodeltype": "RSGUpdate",
                          "operation": "CREATE",
                          "node": {
                            "@graphtype": "Group",
                            "id": "ff483c43-4a36-4197-be49-de829cdd66c8", 
                            "attributes": [
                                  {"key": "name", "value": "Task Specification Tree"},
                                  {"key": "tst:envtst", "value": msg },
                            ],
                          },
                          "parentId": "e379121f-06c6-4e21-ae9d-ae78ec1986a1",
                        }
                  
                        print ("===")
                        print (json.dumps(msg_wm_update))
                        self.zmq_socket.send_string(json.dumps(msg_wm_update)) 

                    else:
                        self.logger.warn("Message is not a dict! Serialization is done here! Msg: \n" + str(msg))
            else:
                self.logger.info("Can't send messages in outbox. Module not ready.")
示例#41
0
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))
示例#42
0
def handle_msg(uuid,name,msg,node):
    print UUID(bytes=uuid),name,msg

if __name__ == '__main__':


    logging.basicConfig(level=logging.DEBUG)
    logger = logging.getLogger("pyre")
    logger.setLevel(logging.INFO)
    logger = logging.getLogger()
    logger.setLevel(logging.DEBUG)

    ctx = zmq.Context()
    n = Pyre("Script")
    n.join('default group')
    n.start()

    poller = zmq.Poller()
    poller.register(n.socket(), zmq.POLLIN)
    try:
        while(True):
            items = dict(poller.poll(timeout=1000))
            if n.socket() in items and items[n.socket()] == zmq.POLLIN:
                cmds = n.recv()
                msg_type = cmds.pop(0)
                msg_type = msg_type.decode('utf-8')
                if msg_type == "SHOUT":
                    uuid,name,group,msg = cmds
                    handle_msg(uuid,name,msg,n)
                elif msg_type == "WHISPER":
示例#43
0
    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()
示例#44
0
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
示例#45
0
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()
示例#46
0
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()
示例#47
0
    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()