How to achieve a non-blocking WebSocket message listener?

I am trying to figure out how to be able to listen for incoming messages over a WebSocket connection without blocking the game execution.

In my attempt to implement this I have used the lua-websocket_example the by @britzl, which in turn is based on lua-websockets. After some reading, my approach was to use a timeout and a coroutine, and in short my code looks like this:

-- game.script:
local websocket = require("websocket")

function init(self)
    self.ws = websocket.client.new({timeout=1})
    local ok, err = self.ws:connect("ws://gameserver:8080", "")
    self.co = coroutine.create(websocket_read)
end

function update(self, dt)
    local status, server_message = coroutine.resume(self.co, self)
    if status and server_message ~= nil then
        msg.post("#gui", "server_message", server_message)
    end
end

function websocket_read(self)
    while true do
        local message, opcode, was_clean, code, reason = self.ws:receive()
        if message ~= nil then
            coroutine.yield(message)
        else
            print("WS rcve:", message, opcode, was_clean, code, reason) -- debug print
            coroutine.yield()
        end
    end
end

The problem here is that after the first read times out, any following atempt to receive a message gives the error “1006 wrong state”. If the timeout is reduced to zero it fails with timeout already when trying to connect; and if no timeout is used, the read is blocking the rest of the program while waiting for a new message.

Is there anyone here who has successfully implemented a non-blocket WebSocket message listener?
Any help to figure out how to solve this is much appreciated!

I also have some interest in how this got resolved.

Boosting this thread.

Someone solve this problem or finded another websocket solution?
Try to find/create websocket with next interface:
async: ws.on_message(set function)

Ok. Thanks to jcash in the defold.slack. Got the first working solution:

Before receive on sync websocket, need to check if it ready for reading with socket.select. Got the next code:
(in the update, not coroutines)

local sockets = {self.wsc.sock};
local rdy_sockets = socket.select(sockets, nil, 0);
if #rdy_sockets ~= 0 then
	local message, opcode, was_clean, code, reason = self.wsc:receive()
	if  message ~= nil then
		print(message);
	end
end

so, any improvements?
also, websockets is not working on HTML5 builds? Is is possible to fix it?
edit: ok, in HTML5 version in lua no bit operations module to handshakes. Can i fix it or need to engine update?
edit2: I have all bit operations now, but cant connect to my server anyway. “WebSocket connection to ‘ws://localhost:7590/’ failed: WebSocket is closed before the connection is established.” Error: connection timeout. Even timeout set to the biig number. But it is theme to another topic…

1 Like

I have updated my original example. Read more here: Websockets HTML5

3 Likes