johannchopin
johannchopin

Reputation: 14853

Impossible to send websockets message inside of a class

I plan to write a class WebsocketHandler that wrap the package websockets

This is the code :

import asyncio
import websockets


class WebsocketHandler:
    __connection = None

    def __init__(self):
        asyncio.run(self.__setConnection())

    async def __setConnection(self):
        async with websockets.connect("ws://localhost/your/path") as websocket:
            self.__connection = websocket
            print("Connected")

    def send(self, msg):
        self.__connection.send(msg)
        print("message Send")


ws = WebsocketHandler()
ws.send("message")

For the server part I have another finished script that works (tested with other scripts in other languages) that sends me a message when I have a new connection, when I receive a message and when I have a client disconnection.

When I try it the script connect successfully to my websocket server (script print Connected and on the server side I get a new connection).

I get then a warning in my script

RuntimeWarning: coroutine 'WebSocketCommonProtocol.send' was never awaited 
self.__connection.send(msg)

And then my script print Message send and it stops.

The problem is that on the server side I don't receive the fact of having a message but only the one that tells me that the client is disconnected. Basically the script does not send the message and does not produce an error.

Anyone have any idea what the problem is ?

Upvotes: 2

Views: 1621

Answers (1)

constt
constt

Reputation: 2320

The problem is that the WebsocketHandler class has got only one async method, namely __setConnection, which is run by calling the asyncio.run function. The docs say that

This function always creates a new event loop and closes it at the end.

That is, this is the only place where the async code could be running. Your code creates a websocket connection and closes it just after it prints "Connected". It happens because you call the websockets.connect method with async with as an asynchronous context manager which closes the connection automatically on exit. This is the first flaw, the second one is that the self.__connection.send function is a coroutine and it won't be running until you'll await on it. This is exactly what the error message is telling you about. Here is how you can fix the websocket handler class:

import asyncio
import websockets


class WebsocketHandler(object):

    def __init__(self):
        self.conn = None

    async def connect(self, url):
        self.conn = await websockets.connect(url)

    async def send(self, msg):
        await self.conn.send(msg)

    async def close(self):
        await self.conn.close()


async def main():
    handler = WebsocketHandler()
    await handler.connect('ws://localhost:8765')

    await handler.send('hello')
    await handler.send('world')

    await handler.close()


loop = asyncio.get_event_loop()
loop.run_until_complete(main())

Upvotes: 5

Related Questions