nodemcu / nodemcu-firmware

Lua based interactive firmware for ESP8266, ESP8285 and ESP32

Home Page:https://nodemcu.readthedocs.io

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Websocket support for httpd module (ESP32)

jmattsson opened this issue · comments

Missing feature

Espressif's web server component also provides support for WebSockets. This is currently not exposed via the httpd module.

Justification

Websockets can provide a far more responsive interface than a poll-based one.

Suggested interface

Copied from @pjsg's comments on the httpd PR:

It appears that the Espressif web server just calls the handler function for each websocket message received and then allows you to transmit a response later. In this way it is very similar to the standard processing except that (I think) the callback can send multiple messages back through the websocket.

The differences are that you have to use httpd_ws_recv_frame and httpd_ws_send_frame when interacting with the websocket.

I think that the LUA api should look like:

The handler function is called with two arguments:

the received frame
A context object (table) with a send method on it that can be used for sending response frames. The user program can also attach state variable to this object.

The received frame will be nil if this is the start of a session.

The context object can be saved until later.

The frame (in each direction) is represented by a table with two keys: type and data. The type is either text or binary. The data is a string. Three additional types are used for control frames -- close, ping, pong.

Receiving a close message means that this is the last message that will be received.

Sending a close message will close the connection.

Personally I'd be tempted to see if the interface could be abstracted a bit further so it becomes something like

function route_handler(req, ws)
  ws.on('text', callback_for_text_frame)
  ws.on('binary', callback_for_binary_frame)
  ws.on('close', callback_when_closed)
  ws.send(httpd.WS_TEXT, some_string_data)
  ws.send(httpd.WS_BINARY, some_binary_data)
  ws.close()
  -- if needed/useful, also:
  ws.ping()
  ws.pong()
  ws.on('ping', callback_for_ping)
  ws.on('pong', callback_for_pong)
end

where the ws table can be stashed away for async .send()/.close() later.

That seems reasonable -- I'll have a go at it!