websocket.recv() never returns inside another event loop
Question: I am currently developing a **server** program in Python that uses the
websockets and asyncio packages.

I got a basic script handling websockets working (Exhibit A). This script
locks when waiting for input, which is not what I want.

The solution for this that I imagine is I can start two asynchronous tasks -
one that handles inputs and one that handles outputs - and start them in a
secondary event loop. I had to do some research about coroutines, and I came
up with Exhibit B as a proof of concept for running two things simultaneously
in an event loop.

Now what I'm stuck on is Exhibit C. When I attempted to use this in a
practical scenario with the websockets package, I found that websocket.recv()
never finishes (or the coroutine never un-pauses - I'm not sure what's going
on exactly). In exhibit A it works fine, and I've determined that the
coroutine definitely runs at least up until that point.

Any ideas?

Exhibit A:

    
    
    #!/usr/bin/python3
    
    import asyncio
    import websockets
    import time
    
    # This works great!
    async def hello(websocket, path):
        while True:
            # This line waits for input from socket
            name = await websocket.recv()
            print("< {}".format(name))
    
            # "echo... echo... echo... echo... echo..."
            greeting = ''.join(name + "... " for x in range(5))
            await websocket.send(greeting)
            print("> {}".format(greeting))
    
            time.sleep(0.1);
    
    start_server = websockets.serve(hello, '', 26231)
    
    asyncio.get_event_loop().run_until_complete(start_server)
    asyncio.get_event_loop().run_forever()
    

Exhibit B:

    
    
    #!/usr/bin/python3
    import asyncio
    import time
    
    class Thing:
        def __init__(self):
            pass
        async def test(self):
            for x in range(10):
                print("Hello"+str(x))
                await asyncio.sleep(0)
        def run(self):
            # Add the task to the event loop twice
            asyncio.ensure_future(self.test())
            asyncio.ensure_future(self.test())
    
    t = Thing()
    t.run()
    
    loop = asyncio.get_event_loop();
    loop.run_forever()
    

Exhibit C:

    
    
    #!/usr/bin/python3
    import asyncio
    import websockets
    import time
    
    class WebsocketRequest:
        def __init__(self, websocket):
            self.websocket = websocket
    
        # Works great
        async def handle_oputs(self):
            # This works fine - sends a message
            #  every 10 seconds to the client
            while True:
                print("sending...")
                await self.websocket.send("Hello")
                print("> {}".format("Hello"))
                time.sleep(10)
    
        # Doesn't work
        async def handle_iputs(self):
            # This stops at the await and never receives
            #  any input from the client :/
            while True:
                try:
                    print("receiving...")
                    # This is the line that causes sadness
                    data = await self.websocket.recv()
                    print("< {}".format(data))
                except:
                    # This doesn't happen either
                    print("Listener is dead")
    
        async def run(self):
    
            # This is the part where the coroutine for
            #  a client get split off into two of them
            #  to handle input and output separately.
            loop = asyncio.new_event_loop()
    
            asyncio.set_event_loop(loop)
            asyncio.ensure_future(self.handle_iputs())
            asyncio.ensure_future(self.handle_oputs())
    
            loop.run_forever()
    
    class WebsocketServer:
        def __init__(self, address):
            self.ip = address[0]
            self.port = address[1]
    
    
        async def hello(self, websocket, path):
            req = WebsocketRequest(websocket)
            await req.run()
    
        def run(self):
            loop = asyncio.new_event_loop()
            asyncio.set_event_loop(loop)
    
            start_server = websockets.serve(self.hello, self.ip, self.port)
    
            asyncio.get_event_loop().run_until_complete(start_server)
            asyncio.get_event_loop().run_forever()
    


Answer: Maybe the module websocket (unlike websockets) can help you.

The use of WebsocketApp is very simple:

    
    
    from websocket import WebSocketApp    
    
    class ExampleClass(object):
        def __init__(self):
            websocket.enableTrace(True)
            self.ws = websocket.WebSocketApp("ws://echo.websocket.org",
                                        on_message=on_message,
                                        on_error=on_error,
                                        on_close=on_close)
    
        def on_message(ws, msg):
            print "Message Arrived:" + msg
    
        def on_error(ws, error):
            print error
    
        def on_close(ws):
            print "Connection Closed"
    
        def on_open(ws):
           ws.send("Hello!")
    

To download this module: <https://pypi.python.org/pypi/websocket-client>

