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)
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
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)
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]
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]
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]