Websocket client with Python cmd


I’m trying to run a websocket client alongside the python cmd library, basically taking input from the user and converting it to a websocket message. The problem is both libraries run an event loop.

I tried using crochet with the “@run_in_reactor” feature but it’s not working. It seems like it might be a problem with my client protocol class but it looks complete based on the docs I’ve been working from. Reactor starts as expected and the client successfully connects to the server but when I try to call sendMessage, I get the following error:

Unhandled Error
Traceback (most recent call last):
  File "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.7/lib/python3.7/threading.py", line 865, in run
    self._target(*self._args, **self._kwargs)
  File "/Users/tomd/havoc/lib/python3.7/site-packages/crochet/_eventloop.py", line 412, in <lambda>
    target=lambda: self._reactor.run(installSignalHandlers=False),
  File "/Users/tomd/havoc/lib/python3.7/site-packages/twisted/internet/base.py", line 1283, in run
  File "/Users/tomd/havoc/lib/python3.7/site-packages/twisted/internet/base.py", line 1292, in mainLoop
--- <exception caught here> ---
  File "/Users/tomd/havoc/lib/python3.7/site-packages/twisted/internet/base.py", line 886, in runUntilCurrent
    f(*a, **kw)
  File "./havoc.py", line 62, in sendTask
  File "/Users/tomd/havoc/lib/python3.7/site-packages/autobahn/websocket/protocol.py", line 2215, in sendMessage
    if self.state != WebSocketProtocol.STATE_OPEN:
builtins.AttributeError: 'HavocClientProtocol' object has no attribute 'state'

My imports:
from cmd import Cmd
from crochet import setup, run_in_reactor, retrieve_result, TimeoutError

# Setup crochet before importing twisted

from twisted.internet import reactor, ssl
from twisted.python import log
from autobahn.twisted.websocket import WebSocketClientFactory, \
    WebSocketClientProtocol, \

This is my ClientProtocol and ClientFactory:

class HavocClientProtocol(WebSocketClientProtocol):

    def __init__(self):
        super(HavocClientProtocol, self).__init__()

    def onConnect(self, response):
        print("Connected to havocops.io")

    def onMessage(self, payload, isBinary):
        if not isBinary:
            print('Message received: {}'.format(payload.decode('utf8')))

    def sendTask(self, payload):
        payload = json.dumps(payload, ensure_ascii = False).encode('utf8')

class HavocClientFactory(WebSocketClientFactory):

    def __init__(self):
        super(HavocClientFactory, self).__init__()

    def buildFactory(self, uri, headers):
        factory = WebSocketClientFactory(uri, headers=headers)
        factory.protocol = HavocClientProtocol
        return factory

And this is how I’m calling it:

if __name__ == '__main__':

    def start_connectWS():
        headers = {'api_key': api_key, 'secret_key': secret_key}
        f = HavocClientFactory()
        connectStatement = f.buildFactory(uri, headers)
        if connectStatement.isSecure:
            contextFactory = ssl.ClientContextFactory()
            contextFactory = None
        connectWS(connectStatement, contextFactory)


If I’m on the wrong path, what is the recommended approach to background the websocket client and call sendMessage from another class? If it seems like I don’t know what the hell I’m doing, it’s because I don’t! Any guidance would be greatly appreciated. :slight_smile:


Are you trying to run two Twisted reactors? (What is the other event-loop?)

yeah, as meejah mentions, the answer depends on

“The problem is both libraries run an event loop.”

Is it one and the same loop? Two different loops, one of mainthread, another on a background thread? Two loops using different networking stacks or the same? …