def test_context_add_2_listeners(self): ws = self.test_ws OTHER_WS = WebSocket(self.mock_socket, self.environ) ctx = self.ctx ctx.add_listener(ws) ctx.add_listener(OTHER_WS) eq_(len(ctx.listeners), 2)
def setUp(self): self.mock_socket = s = mock.Mock() self.environ = env = dict(HTTP_ORIGIN='http://localhost', HTTP_WEBSOCKET_PROTOCOL='ws', PATH_INFO='test') self.test_ws = WebSocket(s, env) super(TestWebSocketObject, self).setUp()
def setUp(self): self.ctx = WebSocketAwareResource() self.mock_socket = s = mock.Mock() self.environ = env = dict(HTTP_ORIGIN='http://localhost', HTTP_WEBSOCKET_PROTOCOL='ws', PATH_INFO='test') self.test_ws = WebSocket(s, env)
def __init__(self, sock ): resp = httplib.HTTPResponse( sock, method='GET' ) resp.begin() self.status = resp.status environ = { 'HTTP_ORIGIN': resp.getheader( 'HTTP_ORIGIN', '' ), 'HTTP_WEBSOCKET_PROTOCOL': resp.getheader( 'HTTP_WEBSOCKET_PROTOCOL', '' ), 'PATH_INFO': resp.getheader( 'PATH_INFO', '' ) } self.sock = WebSocket( sock=sock, environ=environ, version=0 )
def __send_error(self, ws: WebSocket, error: Errors, info: dict = None): """ Send an error to a client via the WebSocket connection. :param ws: WebSocket object. :param error: Error which has occurred. :param info: Additional info about the error if needed. :return: """ # log the error being sent self.logger.warning("Error being sent to client: '" + str(error.value) + "' | info: '" + str(info) + "'") # send the error to the client via the websocket ws.send( self.encoder.encode("error", { "error": error.value, "info": info }))
def test_context_add_listeners(self): ws = self.test_ws OTHER_WS = WebSocket(self.mock_socket, self.environ) ctx = self.ctx eq_(ctx.listeners, set()) ctx.add_listener(ws) eq_(ctx.listeners, set([ws])) ctx.add_listener(ws) eq_(ctx.listeners, set([ws])) ctx.remove_listener(OTHER_WS) eq_(ctx.listeners, set([ws])) ctx.remove_listener(ws) eq_(ctx.listeners, set())
class WebSocketResponse( object ): def __init__(self, sock ): resp = httplib.HTTPResponse( sock, method='GET' ) resp.begin() self.status = resp.status environ = { 'HTTP_ORIGIN': resp.getheader( 'HTTP_ORIGIN', '' ), 'HTTP_WEBSOCKET_PROTOCOL': resp.getheader( 'HTTP_WEBSOCKET_PROTOCOL', '' ), 'PATH_INFO': resp.getheader( 'PATH_INFO', '' ) } self.sock = WebSocket( sock=sock, environ=environ, version=0 ) def send( self, message ): result = self.sock.send( message ) eventlet.sleep(0.001) return result def recv( self ): result = self.sock.wait() eventlet.sleep(0.001) return result def close( self ): sock.close() eventlet.sleep(0.01)
def socket(self, ws: WebSocket): # parse out client information from url args = parse(environ=ws.environ) # get headers headers = dict(ws.environ["headers_raw"]) """ for key, value in headers.items(): print(key + ": ", value) """ # if id is omitted if "IoT-IO-Id" not in headers.keys(): # send error message to client self.__send_error(ws, Errors.CLIENT_NO_ID) raise ClientNoId() # if type is omitted if "IoT-IO-Type" not in headers.keys(): # send error message to client self.__send_error(ws, Errors.CLIENT_NO_TYPE) raise ClientNoType() # if protocol version is omitted if "IoT-IO-ProtocolVersion" not in headers.keys(): # send error message to client self.__send_error(ws, Errors.CLIENT_NO_PROTOCOL_VERSION) raise ClientNoProtocolVersion() # if data is omitted populate with default value if "IoT-IO-Data" not in headers.keys(): headers["IoT-IO-Data"] = "{}" # if endpoints are omitted populate with default value if "IoT-IO-Endpoints" not in headers.keys(): headers["IoT-IO-Endpoints"] = "[]" # deserialize headers try: headers["IoT-IO-Data"] = json.loads(headers["IoT-IO-Data"]) except json.JSONDecodeError: # send error message to client self.__send_error(ws, Errors.CLIENT_INVALID_DATA) raise ClientInvalidData() try: headers["IoT-IO-Endpoints"] = json.loads( headers["IoT-IO-Endpoints"]) except json.JSONDecodeError: # send error message to client self.__send_error(ws, Errors.CLIENT_INVALID_ENDPOINTS, { "endpointId": "", "endpointProblem": "invalid_json" }) raise ClientInvalidEndpoints() # check if the client's protocol version matches that of the server if headers["IoT-IO-ProtocolVersion"] != __protocol_version__: # send error message to client self.__send_error(ws, Errors.CLIENT_INCOMPATIBLE_PROTOCOL_VERSION) raise ClientIncompatibleProtocolVersion() # check if the client has a valid type if self.__types.get(headers["IoT-IO-Type"], None) is None: # log and exit if the client has an invalid type self.logger.warning( "Client with ID '" + args["id"] + "' claimed a device type of '" + args["type"] + "' but no such device type was defined. Refusing connection.") # send error message to client self.__send_error(ws, Errors.CLIENT_INVALID_TYPE) # abort connection raise ClientInvalidType() # remove a client with the same id if it exists (getting rid of ghost clients) self.remove(headers["IoT-IO-Id"]) # create a new client client = IoTClient(ws, headers["IoT-IO-Id"], headers["IoT-IO-Type"], headers["IoT-IO-Data"], self, logging_level=self.client_logging_level, encoder=self.encoder) # parse endpoints endpoint_id, response = client.parse_endpoints( headers["IoT-IO-Endpoints"]) if response != EndpointParseResponse.VALID: self.__send_error(ws, Errors.CLIENT_INVALID_ENDPOINTS, { "endpointId": endpoint_id, "endpointProblem": response.value }) raise ClientInvalidEndpoints() self.add(client) # client loop try: data = "" while data is not None: # wait for message from the websocket data = ws.wait() # if the message is None check if the connection is closed if data is None: break # decode received message event, message = self.encoder.decode(data) # call the callback associated with the event event, response = self.__handle_event_message( event, message, client) # check if there is a response to send to the client if response is not None: try: client.emit(event, response) except ConnectionEnded: return except BrokenPipeError: pass finally: self.remove(client)