pythonwebsockettwistedtwisted.webtwisted.internet

How to set subprotocol list for Client (Twisted)


Hey everyone,

I have created a Client and a Server to communicate over websockets. The Twisted library is used for the websockets, and eventually I will be sending GraphQL strings from Client to Server.

However, I am getting an error that states:

failing WebSocket opening handshake ('subprotocol selected by server (graphql-ws) not in subprotocol list requested by client ([])')

Here is the example code that I have created:

server.py

class MyServerProtocol(WebSocketServerProtocol):

  def onConnect(self, request):
    custom_header = {}
    if request.headers['sec-websocket-key']:
      custom_header['sec-websocket-protocol'] = 'graphql-ws'
    return (None, custom_header)

  def onOpen(self):
    print "Websocket connection open"

  def onMessage(self, payload, isBinary):
    # Handle GraphQL query string here
    try:
      parsed_message = json.loads(payload)
    except Exception as exp:
      logger.error('Could not parse websocket payload', exc_info=True)
      self.sendClose()
      return 1

  def onClose(self, wasClean, code, reason):
    print("WebSocket connection closed: {0}".format(reason))

client.py

class MyClientProtocol(WebSocketClientProtocol):

  def onConnect(self, response):
    response.protocol = 'graphql-ws'

  def onOpen(self):
    print "Websocket connection open"

  def onMessage(self, payload, isBinary):
    if isBinary:
        print("Binary message received: {0} bytes".format(len(payload)))
    else:
        print("Text message received: {0}".format(payload.decode('utf8')))

  def onClose(self, wasClean, code, reason):
    print("WebSocket connection closed: {0}".format(reason))

Does anyone know how to set the subprotocol list on the Client side? Any help would be greatly appreciated.

Thanks,

Brian


Solution

  • After you created the factory, you can append custom sub-protocols:

    factory = WebSocketClientFactory("wss://SERVER_URL")
    factory.protocol = MyClientProtocol
    
    # append custom protocols here:
    factory.protocols.append("graphql-ws")
    
    connectWS(factory)
    

    Be careful with the "s" (protocol <=> protocols). You can check if the protocol has been accepted by the server in the response of the "onConnect" method:

    def OnConnect(self, response):
         print(response)
    
    output: {"peer" : "...", "headers" : { ... }, "protocol": "graphql-ws", ...}