lua nginx websocket

on 2015-01-29

Nginx like a lot of projects can be extended with Lua scripts very easily.

lua-resty-websocket library is part of openresty project and started to package it for Debian.

In this short post, I will present how to have a simple WebSocket server that pulls data from Redis.

You will need nginx-extras lua-nginx-websocket lua-nginx-redis redis-server packages from Debian.

You can have an Nginx config like that for example:

server {
        server_name websocket.test;
        set $app_root /u/websocket-test;

        location ~ /s {
                content_by_lua_file $app_root/websocket.lua;
        }
}

And the websocket.lua file:

local server = require "nginx.websocket.server"
local redis = require "nginx.redis"

-- websocket server
local wb, err = server:new{
    timeout = 5000,  -- in milliseconds
    max_payload_len = 65535,
}
if not wb then
    ngx.log(ngx.ERR, "failed to new websocket: ", err)
    return ngx.exit(444)
end

-- redis connection
local rd = redis:new()
local ok, err = rd:connect('127.0.0.1', 6379)
if not ok then
    ngx.log(ngx.ERR, "failed to redis connect: ", err)
    return ngx.exit(444)
end

After the init, we will get data from redis and send it to the websocket client.

while true do
    local data, typ, err = wb:recv_frame()

    local list = "websocket-test"
    local res, err = rd:lpop(list)
    while res ~= ngx.null do
        bytes, err = wb:send_text(res)
        if not bytes then
            ngx.log(ngx.ERR, "failed to send a text frame: ", err)
            return ngx.exit(444)
        end
        res, err = rd:lpop(list)
    end

    -- [...]
end

wb:send_close()
rd:close()

Now on the JavaScript client.

var socket = new WebSocket('ws://'+ window.location.hostname + '/s');
socket.onmessage = function(event) {
    data = JSON.parse(event.data);
    // [...]
};

For testing, you can use redis-cli monitor and another command to insert data on the Redis list.

redis-cli rpush websocket-test '{"timestamp":"2014-08-24T19:59:48.513890", "channel":"#test","nick":"USER","url":"https://github.com/openresty/lua-nginx-module#ngxthreadspawn"}'

Edit: Experiment project znc-urltimeline