class RCERobotProtocol(WebSocketClientProtocol): """ WebSocket client protocol which is used to communicate with the Robot Manager. """ def __init__(self, connection): """ Initialize the protocol. @param connection: Connection instance which provides callback functions. @type connection: pyrce.connection._Connection """ self._connection = connection self._assembler = MessageAssembler(self, 60) self._registered = False def onOpen(self): """ This method is called by twisted as soon as the websocket connection has been successfully established. """ self._assembler.start() self._connection.registerConnection(self) self._registered = True def onMessage(self, msg, binary): """ This method is called by twisted when a new message has been received. """ self._assembler.processMessage(msg, binary) def processCompleteMessage(self, msg): """ Callback for MessageAssembler which will be called as soon as a message has been completed and is ready for processing. """ self._connection.receivedMessage(msg) def onClose(self, *a): """ This method is called by twisted when the connection has been closed. """ if self._registered: self._connection.unregisterConnection(self) self._assembler.stop() self._registered = False def failHandshake(self, reason): """ This method is called by twisted when the connection could not be initialized. """ print(reason) WebSocketClientProtocol.failHandshake(self, reason)
class RobotWebSocketProtocol(WebSocketServerProtocol): """ Protocol which is used for the connections from the robots to the robot manager. """ def __init__(self, manager): """ Initialize the Protocol. """ self._manager = manager self._userID = None self._robotID = None self._msgHandler = {} self._assembler = MessageAssembler(self, definition.MSG_QUEUE_TIMEOUT) def onConnect(self, req): """ Method is called by the Autobahn engine when a request to establish a connection has been received. @param req: Connection Request object. @type req: autobahn.websocket.ConnectionRequest @raise: autobahn.websocket.HttpException """ params = req.params try: userID = params['userID'] robotID = params['robotID'] key = params['key'] except KeyError as e: raise HttpException(httpstatus.HTTP_STATUS_CODE_BAD_REQUEST[0], 'Request is missing parameter: {0}'.format(e)) for name, param in [('userID', userID), ('robotID', robotID), ('key', key)]: if len(param) != 1: raise HttpException(httpstatus.HTTP_STATUS_CODE_BAD_REQUEST[0], "Parameter '{0}' has to be unique in " 'request.'.format(name)) userID = userID[0] robotID = robotID[0] key = key[0] try: self._manager.robotConnected(userID, robotID, key, self) except AuthenticationError as e: raise HttpException(httpstatus.HTTP_STATUS_CODE_FORBIDDEN[0], str(e)) except Exception as e: import traceback raise HttpException( httpstatus.HTTP_STATUS_CODE_INTERNAL_SERVER_ERROR[0], traceback.format_exc() ) self._robotID = robotID self._userID = userID # TODO: List should probably not be hard coded here, # but given as an argument... for handler in [ CreateContainerHandler(self._manager, userID), DestroyContainerHandler(self._manager, userID), ConfigureContainerHandler(self._manager, userID), ConnectInterfacesHandler(self._manager, userID), DataMessageHandler(self._manager, userID) ]: verifyObject(IClientMsgHandler, handler) self._msgHandler[handler.TYPE] = handler self._assembler.start() return None def processCompleteMessage(self, msg): """ Process complete messages by calling the appropriate handler for the manager. (Called by client.protocol.BinaryAssembler) """ try: msgType = msg['type'] data = msg['data'] except KeyError as e: raise InvalidRequest('Message is missing key: {0}'.format(e)) try: self._msgHandler[msgType].handle(data) except KeyError as e: raise InvalidRequest('This message type is not supported.') def onMessage(self, msg, binary): """ Method is called by the Autobahn engine when a message has been received from the client. """ log.msg('WebSocket: Received new message from client. ' '(binary={0})'.format(binary)) resp = None try: self._assembler.processMessage(msg, binary) except InvalidRequest as e: #resp = 'Invalid Request: {0}'.format(e) import traceback resp = traceback.format_exc() msgType = types.ERROR except AuthenticationError as e: #resp = 'Authentication Error: {0}'.format(e) import traceback resp = traceback.format_exc() msgType = types.ERROR except Exception as e: # TODO: Refine Error handling #import sys, traceback #WebSocketServerProtocol.sendMessage(self, '\n'.join( # traceback.format_exception_only(type(e), e))) # Full debug message import traceback resp = traceback.format_exc() msgType = types.ERROR if resp: self.sendMessage({'data' : resp, 'type' : msgType}) def sendMessage(self, msg): """ This method is called by the User instance to send a message to the robot. @param msg: Message which should be sent """ uriBinary, msgURI = recursiveBinarySearch(msg) WebSocketServerProtocol.sendMessage(self, json.dumps(msgURI)) for binData in uriBinary: WebSocketServerProtocol.sendMessage(self, binData[0] + binData[1].getvalue(), binary=True) def onClose(self, wasClean, code, reason): """ Method is called by the Autobahn engine when the connection has been lost. """ if self._userID and self._robotID: self._manager.robotClosed(self._userID, self._robotID) self._assembler.stop() self._assembler = None