Exemple #1
0
    def _handle_incoming_zmq(self):
        """Executes in separate thread: _zmq_messaging_thread."""

        # NOTE - We shouldn't need the lock here because access to the
        # zmq socket should ONLY ever happen in one thread (this one!)
        # and logging is already threadsafe - we delegate operations
        # that might need the lock to _handle_zmq_msg().

        # Initialise sockets
        zmq_poller = zmq.Poller()
        zmq_termination_reply_socket = self.zmq_context.socket(zmq.REP)
        zmq_reply_socket = self.zmq_context.socket(zmq.REP)
        zmq_reply_socket.bind(
            ZMQ_ADDRESS_LOCALHOST.format(port=self.zmq_req_port)
        )
        zmq_termination_reply_socket.bind(
            ZMQ_ADDRESS_INPROC.format(
                identifier=self.zmq_manager_term_identifier
            )
        )
        zmq_poller.register(zmq_reply_socket, zmq.POLLIN)
        zmq_poller.register(zmq_termination_reply_socket, zmq.POLLIN)

        # Provide a method to loop over sockets that have data
        def _loop_over_sockets():
            term = False
            for sock in socks_with_data:
                if sock is zmq_termination_reply_socket:
                    term = True
                elif not term:  # If we're not in the process of terminating...
                    msg = sock.recv().decode()
                    reply = self._handle_zmq_msg(msg)
                    if reply is None:
                        log.warning(WARN_NO_REPLY)
                        reply = self._encapsulate_reply(self._generate_error())
                    sock.send(ElementTree.tostring(reply))
            return term

        # Poll for messages
        while True:
            socks_with_data = dict(zmq_poller.poll())
            if socks_with_data:
                term = _loop_over_sockets()
                if term:
                    break

        # Cleanup ZMQ
        zmq_poller.unregister(zmq_reply_socket)
        zmq_poller.unregister(zmq_termination_reply_socket)
        zmq_reply_socket.close()
        zmq_termination_reply_socket.close()
    def __init__(self):
        """Default constructor - Creates a new SensorManager."""
        description = "Manage Yarely sensors"

        # The parent constructor provides config and logging and gets a
        # starting set of handlers using this classes _init_handlers() method.
        super().__init__(ZMQ_SENSORMANAGER_REP_PORT, description)
        self.registered = False

        # Setup for ZMQ Scheduler Messaging
        sensor_term_id = "sensormanager_term_{id}"
        self.zmq_sensormanager_term_identifier = sensor_term_id.format(
            id=id(self))
        self.zmq_scheduler_req_addr = ZMQ_ADDRESS_LOCALHOST.format(
            port=ZMQ_SENSORMANAGER_REQ_PORT)
        self.zmq_scheduler_request_queue = queue.Queue()  # Q of infinite size
Exemple #3
0
    def start_handler(self, handler_stub):
        """Start a new subprocess (Handler) using the specified command
        line arguments. Once it is started and has registered over ZMQ it
        will be sent the specified params via ZMQ.

        :param handler_stub: the uri string to be matched.
        :type handler_stub: a :class:`~manager.HandlerStub` instance that
            describes the Handler to be started.
        :return: the subprocess ID for the newly started Handler.
        :rtype: int

        """
        handler = copy.deepcopy(handler_stub)
        params_over_zmq = handler.params_over_zmq if hasattr(
            handler, 'params_over_zmq'
        ) else dict()
        command_line_args = handler.command_line_args if hasattr(
            handler, 'command_line_args'
        ) else list()
        command_line_args.append(
            ZMQ_ADDRESS_LOCALHOST.format(port=self.zmq_req_port)
        )
        subproc = SubprocessExecutionWithErrorCapturing(
            command_line_args, params_over_zmq
        )
        with self._lock:
            if (
                self._stop_request.is_set() or
                not self._handler_status_check_thread.is_alive()
            ):
                msg = ('Cannot start handler - handler status checker stopped '
                       'or stopping')
                raise ManagerNotExecutingError(msg)
            subprocess_id = subproc.start()
            self._executing_handlers[subprocess_id] = subproc
        return subprocess_id
 def _make_client(self):
     self.client = self.context.socket(zmq.REQ)
     self.client.connect(
         ZMQ_ADDRESS_LOCALHOST.format(port=ZMQ_DISPLAYCONTROLLER_REP_PORT))
     self.poll.register(self.client, zmq.POLLIN)
Exemple #5
0
    def _handle_incoming_zmq(self):
        """Handles incoming requests. Uses _handle_zmq_messages to map requests
        on to methods.

        """
        # Create reply socket to subscription manager
        zmq_subsmanager_reply_socket = self.zmq_context.socket(zmq.REP)
        zmq_subsmanager_reply_socket.setsockopt(
            zmq.LINGER, ZMQ_SOCKET_LINGER_MSEC
        )
        zmq_subsmanager_reply_socket.bind(
            ZMQ_ADDRESS_LOCALHOST.format(port=ZMQ_SUBSMANAGER_REQ_PORT)
        )

        # Create a reply socket to the sensor manager
        zmq_sensormanager_reply_socket = self.zmq_context.socket(zmq.REP)
        zmq_sensormanager_reply_socket.setsockopt(
            zmq.LINGER, ZMQ_SOCKET_LINGER_MSEC
        )
        zmq_sensormanager_reply_socket.bind(
            ZMQ_ADDRESS_LOCALHOST.format(port=ZMQ_SENSORMANAGER_REQ_PORT)
        )

        # Create termination socket
        zmq_termination_reply_socket = self.zmq_context.socket(zmq.REP)
        zmq_termination_reply_socket.bind(
            ZMQ_ADDRESS_INPROC.format(
                identifier=self.zmq_scheduler_term_identifier
            )
        )

        # Register all sockets
        zmq_poller = zmq.Poller()
        zmq_poller.register(zmq_subsmanager_reply_socket, zmq.POLLIN)
        zmq_poller.register(zmq_sensormanager_reply_socket, zmq.POLLIN)
        zmq_poller.register(zmq_termination_reply_socket, zmq.POLLIN)

        # Provide a method to loop over sockets that have data. It tries to
        # find matching methods for incoming requests/replies with
        # _handle_zmq_msg().
        def _loop_over_sockets():
            term = False

            for sock in socks_with_data:
                if sock is zmq_termination_reply_socket:
                    return True

                msg = sock.recv().decode()
                reply = self._handle_zmq_msg(msg)

                # Check if we got a valid reply from the method called.
                if reply is None:
                    log.warning(
                        "No reply generated, replying with error!"
                    )
                    reply = self._encapsulate_reply(self._generate_error())

                sock.send(ElementTree.tostring(reply))

            return term

        # Look at all incoming messages
        while True:
            socks_with_data = dict(zmq_poller.poll())

            if socks_with_data:
                term = _loop_over_sockets()

                if term:
                    break

        # Cleanup ZMQ
        zmq_poller.unregister(zmq_subsmanager_reply_socket)
        zmq_poller.unregister(zmq_sensormanager_reply_socket)
        zmq_poller.unregister(zmq_termination_reply_socket)
        zmq_subsmanager_reply_socket.close()
        zmq_sensormanager_reply_socket.close()
        zmq_termination_reply_socket.close()
_TERMINATION_MARKER = object()
QUEUE_TIMEOUT = 1  # Seconds
WARN_NO_REPLY = 'Expected reply from Scheduler not received.'
DISPLAY_STATE_POLLING_FREQ = 3  # Seconds

# FIXME path
DISPLAY_DEVICE_DIRECTORY = os.path.abspath(
    __file__)[:-len('display_controller.py')]
DISPLAY_DEVICE_DRIVER_SUFFIX = '_display_device.py'
DISPLAY_IS_ON = "IS_ON"
DISPLAY_IS_OFF = "IS_OFF"
DISPLAY_UNKNOWN_STATE = "UNKNOWN_STATE"

LINESPEED_DISPLAY = termios.B9600
# FIXME
ZMQ_SCHEDULER_ADDR = ZMQ_ADDRESS_LOCALHOST.format(
    port=ZMQ_DISPLAYCONTROLLER_REP_PORT)


class DisplayControllerError(Exception):
    """Base class for display controller errors"""
    pass


class DisplayController(threading.Thread):
    """ Starts a thread that can send power commands to the display
    asynchronously.

    """
    def __init__(self,
                 display_serial,
                 analytics_tracking_id,
Exemple #7
0
    def _start_renderer(self, item, position, layout=None):
        """ Find the appropriate renderer for the content item, initialise it
        with an optional layout, find cached path to the content item and start
        the renderer subprocess.
        :param item: Content Item instance to be shown on the screen.
        :param layout: Optional layout attributes (see display_item).
        :param position: Optional position attribute (see display_item).
        :return: subprocess ID.
        """

        # Get initial args and find the right renderer.
        # We also give the renderer a unique ID that it will use to communicate
        # back to Display Manager.
        args = get_initial_args(item.get_content_type())
        module = ARG_RENDER_NAMESPACE + args['module']
        renderer_uuid = str(uuid.uuid4())
        cmd_args = [
            self._get_yarely_module_starter_path(), '-m', module,
            '--uuid', renderer_uuid,
            ZMQ_ADDRESS_LOCALHOST.format(port=ZMQ_RENDERER_REQ_PORT)
        ]

        # We take the first URI from the content item to display.
        item_uri = str(item)

        # Try to get the item from the cache and overwrite its URI.
        if 'precache' in args and args['precache']:
            item_uri = self.cache.file_cached(item, strict=False)

        # Validate item_uri to make sure it can be scheduled at all
        if item_uri is None:
            raise RendererError()

        # Check if item_uri really is a URI. Some renderer don't like local
        # paths and prefer URIs (file://) instead.
        if (
            'param_type' in args and
            args['param_type'] == 'uri' and
            True not in (item_uri.startswith('http'),
                         item_uri.startswith('udp'),
                         item_uri.startswith('file'),
                         item_uri.startswith('rtmp'))
        ):
            item_uri = platform.get_uri_from_local_path(item_uri)

        # Prepare the new renderer and start it
        log.info('Starting new renderer: {args!s}'.format(args=cmd_args))
        params_over_zmq = {args['param_type']: item_uri}

        # Add the layout
        if layout is not None:
            params_over_zmq.update(layout)

        logging.debug("Send params over ZMQ: {}".format(params_over_zmq))

        subp = SubprocessExecutionWithErrorCapturing(
            cmd_args, params_over_zmq
        )

        # Start the renderer and store the reference in _executing_renderers.
        subprocess_id = subp.start()

        # Save the reference to the new renderer.
        renderer = ExecutingRenderer(subp, position, renderer_uuid, item)

        with self._renderers_lock:
            self._renderers[renderer_uuid] = renderer

        return subprocess_id