Exemplo n.º 1
0
    def _parse_request(self, bottle):
        """
        Parse the incoming bottle.
        """
        try:
            request_msg = bottle.get(0).toString()
            request = json.loads(request_msg, object_pairs_hook=OrderedDict)
        except (IndexError, ValueError) as e:
            raise MorseRPCInvokationError(
                'Malformed request: expected a json econded request with this format: \'{id:13, component:Motion_Controller, service:goto, params:[5, 5, 0]}\' (all values enclosed in strings)'
            )

        id = request['id']
        component_name = request['component']
        service = request['service']
        try:
            params = request['params']
            import ast
            p = ast.literal_eval(params)
        except (NameError, SyntaxError) as e:
            raise MorseRPCInvokationError(
                "Invalid request syntax: error while parsing the parameters. "
                + str(e))

        return (id, component_name, service, p)
Exemplo n.º 2
0
    def _parse_request(self, req):
        """
        Parse the incoming request.
        """

        tokens = req.split(None, 2)

        if len(tokens) < 1 or len(tokens) > 3:
            raise MorseRPCInvokationError("Malformed request: at least 3 values and at most 4 are expected (id, component, service, [params])")

        if len(tokens) == 2:
            component, service = tokens
            p = None
        else:
            component, service, params = tokens
            
            params = params.strip()

            if params:
                try:
                    p =  json.loads(params)
                except (NameError, SyntaxError, ValueError) as e:
                    raise MorseRPCInvokationError("Invalid request syntax: error while parsing the parameters: <%s>. %s" % (params, str(e)))
            else:
                p = None
        return component, service, p
Exemplo n.º 3
0
    def _parse_request(self, bottle):
        """
        Parse the incoming bottle.
        """
        try:
            id = bottle.get(0).asInt()
            component_name = bottle.get(1).toString()
            service = bottle.get(2).toString()
        except IndexError as e:
            raise MorseRPCInvokationError("Malformed request: at least 3 values and at most 4 are expected (id, component_name, service, [params])")

        try:
            params = bottle.get(3).toString()
            import ast
            p =  ast.literal_eval(params)
        except (NameError, SyntaxError) as e:
            raise MorseRPCInvokationError("Invalid request syntax: error while parsing the parameters. " + str(e))

        return (id, component_name, service, p)
Exemplo n.º 4
0
    def main(self):
        """ Read commands from the ports, and prepare the response"""
        # Read data from available ports
        for component_name, port in self._yarp_request_ports.items():
            # Get the bottles to read and write
            bottle_in = self._in_bottles[component_name]
            bottle_reply = self._reply_bottles[component_name]
            bottle_in = port.read(False)
            if bottle_in is not None:
                logger.debug("Received command from port '%s'" %
                             (component_name))
                id = 'unknown'

                try:
                    try:
                        id, component_name, service, params = self._parse_request(
                            bottle_in)
                    except ValueError:  # Request contains < 2 tokens.
                        raise MorseRPCInvokationError("Malformed request!")

                    logger.info(
                        "Got '%s | %s | %s' (id = %s) from %s" %
                        (component_name, service, params, id, component_name))

                    # on_incoming_request returns either
                    # (True, result) if it's a synchronous
                    # request that has been immediately executed, or
                    # (False, request_id) if it's an asynchronous request whose
                    # termination will be notified via
                    # on_service_completion.
                    is_sync, value = self.on_incoming_request(
                        component_name, service, params)

                    if is_sync:
                        if port in self._results_to_output:
                            self._results_to_output[port].append((id, value))
                        else:
                            self._results_to_output[port] = [(id, value)]
                    else:
                        # Stores the mapping request/socket to notify
                        # the right port when the service completes.
                        # (cf :py:meth:on_service_completion)
                        # Here, 'value' is the internal request id while
                        # 'id' is the id used by the socket client.
                        self._pending_ports[value] = (port, id)

                except MorseRPCInvokationError as e:
                    if port in self._results_to_output:
                        self._results_to_output[port].append(
                            (id, (status.FAILED, e.value)))
                    else:
                        self._results_to_output[port] = [(id, (status.FAILED,
                                                               e.value))]

        if self._results_to_output:
            for component_name, port in self._yarp_request_ports.items():
                if port in self._results_to_output:
                    for r in self._results_to_output[port]:
                        response = OrderedDict([
                            ('id', r[0]), ('status', r[1][0]),
                            ('reply', (r[1][1] if r[1][1] else ""))
                        ])
                        #('reply', "%s" % str(r[1][1]) if r[1][1] else "") ])
                        json_response = json.dumps(response)
                        # Send the reply through the same yarp port
                        reply_port = self._yarp_reply_ports[component_name]
                        bottle_reply = reply_port.prepare()
                        bottle_reply.clear()
                        bottle_reply.addString(json_response)
                        reply_port.write()
                        logger.debug("Sent back '" + str(response) +
                                     "'. Component: " + component_name +
                                     ". Port: " + str(port))

                    del self._results_to_output[port]
Exemplo n.º 5
0
    def main(self):
        
        sockets = self._client_sockets + [self._server]

        try:
            inputready, outputready, exceptready = select.select(sockets, sockets, [], 0) #timeout = 0 : Never block, just poll
        except select.error:
            pass
        except socket.error:
            pass

        for i in inputready:
            if i == self._server:
                sock, addr = self._server.accept()

                logger.info("Accepted new service connection from " + str(addr))
                self._client_sockets.append(sock)

            else:
                try:
                    raw = i.recv(4096)
                except ConnectionResetError as e:
                    import os
                    if os.name == 'nt' and e.errno == 10054:
                        # An existing connection was forcibly closed by the remote host
                        raw = None
                    else:
                        raise
                if not raw:
                    # an empty read means that the remote host has
                    # disconnected itself
                    logger.info("Socket closed by client! Closing it on my side.")
                    i.close()
                    self._client_sockets.remove(i)
                    continue
                raw = raw.decode()
                assert(raw[-1] == '\n')
                for req in raw[:-1].split('\n'):
                    req = req.strip()

                    component = service = "undefined"

                    try:
                        try:
                            id, req = req.split(None, 1)
                        except ValueError: # Request contains < 2 tokens.
                            id = req
                            raise MorseRPCInvokationError("Malformed request! ")

                        id = id.strip()

                        logger.info("Got '" + req + "' (id = " + id + ") from " + str(i))

                        if len(req.split()) == 1 and req in ["cancel"]:
                            # Aborting a running request!
                            for internal_id, user_id in self._pending_sockets.items():
                                if user_id[1] == id:
                                    self.abort_request(internal_id)

                        else:
                            component, service, params = self._parse_request(req)

                            # on_incoming_request returns either
                            #(True, result) if it's a synchronous
                            # request that has been immediately executed, or
                            # (False, request_id) if it's an asynchronous request whose
                            # termination will be notified via
                            # on_service_completion.
                            is_sync, value = self.on_incoming_request(component, service, params)

                            if is_sync:
                                if i in self._results_to_output:
                                    self._results_to_output[i].append((id, value))
                                else:
                                    self._results_to_output[i] = [(id, value)]
                            else:
                                # Stores the mapping request/socket to notify
                                # the right socket when the service completes.
                                # (cf :py:meth:on_service_completion)
                                # Here, 'value' is the internal request id while
                                # 'id' is the id used by the socket client.
                                self._pending_sockets[value] = (i, id)


                    except MorseRPCInvokationError as e:
                        if i in self._results_to_output:
                            self._results_to_output[i].append((id, (status.FAILED, e.value)))
                        else:
                            self._results_to_output[i] = [(id, (status.FAILED, e.value))]

        if self._results_to_output:
            for o in outputready:
                if o in self._results_to_output:
                    for r in self._results_to_output[o]:
                        return_value = None
                        try:
                            if r[1][1]:
                                return_value = json.dumps(r[1][1], cls=MorseEncoder)
                        except TypeError as te:
                            logger.error("Error while serializing a service return value to JSON!\n" +\
                                    "Details:" + str(te))
                        response = "%s %s%s" % (r[0], r[1][0], (" " + return_value) if return_value else "")
                        try:
                            o.send((response + "\n").encode())
                            logger.info("Sent back " + response + " to " + str(o))
                        except socket.error:
                            logger.warning("It seems that a socket client left while I was sending stuff to it. Closing the socket.")
                            o.close()
                            self._client_sockets.remove(o)

                    del self._results_to_output[o]
Exemplo n.º 6
0
    def main(self):

        sockets = list(self._client_sockets.keys()) + [self._server]

        try:
            inputready, outputready, exceptready = select.select(
                sockets, sockets, [], 0)  #timeout = 0 : Never block, just poll
        except select.error:
            pass
        except socket.error:
            pass

        for i in inputready:
            if i == self._server:
                sock, addr = self._server.accept()

                self._client_sockets[sock] = sock.makefile(
                    "rw"
                )  #convert the socket into a file interface to ease reading
                logger.info("Accepted new service connection from " +
                            str(addr))

            else:
                req = self._client_sockets[i].readline()
                # an empty read means that the remote host has
                # disconnected itself
                if req == '':
                    try:  # close the socket if it gives an error
                        # (this can spawn an other error!)
                        self._client_sockets[i].close()
                    except socket.error as error_info:
                        logger.warning("Socket error catched while closing: " \
                                       + str(error_info))
                    del self._client_sockets[i]
                    continue
                req = req.strip()

                component = service = "undefined"

                try:
                    try:
                        id, req = req.split(" ", 1)
                    except ValueError:  # Request contains < 2 tokens.
                        id = req
                        raise MorseRPCInvokationError("Malformed request! ")

                    id = id.strip()

                    logger.info("Got '" + req + "' (id = " + id + ") from " +
                                str(i))

                    component, service, params = self._parse_request(req)

                    # on_incoming_request returns either
                    #(True, result) if it's a synchronous
                    # request that has been immediately executed, or
                    # (False, request_id) if it's an asynchronous request whose
                    # termination will be notified via
                    # on_service_completion.
                    is_sync, value = self.on_incoming_request(
                        component, service, params)

                    if is_sync:
                        if i in self._results_to_output:
                            self._results_to_output[i].append((id, value))
                        else:
                            self._results_to_output[i] = [(id, value)]
                    else:
                        # Stores the mapping request/socket to notify
                        # the right socket when the service completes.
                        # (cf :py:meth:on_service_completion)
                        # Here, 'value' is the internal request id while
                        # 'id' is the id used by the socket client.
                        self._pending_sockets[value] = (i, id)

                except MorseRPCInvokationError as e:
                    if i in self._results_to_output:
                        self._results_to_output[i].append(
                            (id, (status.FAILED, e.value)))
                    else:
                        self._results_to_output[i] = [(id, (status.FAILED,
                                                            e.value))]

        if self._results_to_output:
            for o in outputready:
                if o in self._results_to_output:
                    for r in self._results_to_output[o]:
                        return_value = None
                        try:
                            if r[1][1]:
                                return_value = json.dumps(r[1][1])
                        except TypeError as te:
                            logger.error("Error while serializing a service return value to JSON!\n" +\
                                    "Details:" + te.value)
                        response = "%s %s%s" % (r[0], r[1][0],
                                                (" " + return_value)
                                                if return_value else "")
                        try:
                            self._client_sockets[o].write(response)
                            self._client_sockets[o].write("\n")
                            self._client_sockets[o].flush()
                            logger.info("Sent back " + response + " to " +
                                        str(o))
                        except socket.error:
                            logger.warning(
                                "It seems that a socket client left. Closing the socket."
                            )
                            try:  # close the socket if it gives an error (this can spawn an other error!)
                                self._client_sockets[o].close()
                            except socket.error as error_info:
                                logger.warning(
                                    "Socket error catched while closing: " +
                                    str(error_info))
                            del self._client_sockets[o]

                    del self._results_to_output[o]