3

I have 3 machines; A, B, C.

A is running a websocket server that C wants to connect to, but C can't connect to A directly. To solve this I want to essentially 'proxy' the websocket through machine B.

A is acting as a publisher and producing new packets every few seconds that I want to push through to C. C does not need to send anything to A (although may be required in the future).

I want to implement this proxy by using the websockets (https://pypi.org/project/websockets/) module. I'm currently trying to create a server on B that listens for connections and keeps websocket connections with any clients. I then want to asynchronously run a websocket client that connects to machine A. This is a subscriber connection and any updates from the websocket connection to A should be pushed through to C (or any other clients connecting to B).

Here is my current (minimal) implementation in which an error occurs.

sockets = set()

def register(websocket):
    sockets.add(websocket)

def unregister(websocket):
    sockets.remove(websocket)

async def update_clients(update):
    if sockets:
        await asyncio.wait([socket.send(update) for socket in sockets])

async def client_server(websocket, path):
    register(websocket)
    await websocket.send("Welcome!")

async def live_updates():
    async with websockets.connect(LIVE_URL) as websocket:
        async for update in websocket.recv():
            await update_clients(update)

webserver = websockets.serve(client_server, "0.0.0.0", PORT)

loop = asyncio.get_event_loop()
loop.run_until_complete(webserver)
loop.run_until_complete(live_updates)
loop.run_forever()

The error is as follows

Traceback (most recent call last):
  File "/usr/lib/python3.6/asyncio/base_events.py", line 1310, in call_exception_handler
    self.default_exception_handler(context)
  File "/usr/lib/python3.6/asyncio/base_events.py", line 1282, in default_exception_handler
    value = repr(value)
  File "/usr/lib/python3.6/asyncio/base_tasks.py", line 15, in _task_repr_info
    coro = coroutines._format_coroutine(task._coro)
  File "/usr/lib/python3.6/asyncio/coroutines.py", line 276, in _format_coroutine
    assert iscoroutine(coro)
AssertionError

1 Answer 1

3

When I remove the second run_until_complete(live_updates) the code runs with no errors. So I removed the first run_until_complete, compared my code to the example code from https://websockets.readthedocs.io/en/stable/intro.html and realised that

run_until_complete(live_updates) should be run_until_complete(live_updates())

I'm leaving this question in case anyone runs up against the same error, as the error message is confusing for a beginner to async.

Sign up to request clarification or add additional context in comments.

1 Comment

If machine B is actually running a websocket using Django Channels, would you know how to achieve the same routing? Basically I want Django Channels server to establish a one-time persistent subscription to the upstream server (server A, in your case) and then route all subsequent incoming data from there to C. I'm already comfortable running Django Channels consumers (websocket server), but I want to know how to combine a websocket client into it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.