Mathias
Mathias

Reputation: 41

Openresty Lua script only works one time

The following code works as intended, but only one time.

require("loadCheckfile")  
require("checkValPairs")
local checklist = loadCheckfile("/home/myname/code/workbench/src/check.lst")

local keyList = {}
local valList = {}

-- Load GET arguments into tables
local args = ngx.req.get_uri_args()
for key, val in pairs(args) do
    table.insert(keyList, key)
    table.insert(valList, val)
end

-- show values in table (just for testing)
ngx.say(unpack(keyList))
ngx.say(unpack(valList))


local key1

-- search for keywords and look them up in the checklist
for i = 1, table.maxn(keyList) do
    if keyList[i] == "user" then
        key1 = i
        for j = 1, table.maxn(keyList) do
            if keyList[j] == "pass" then
                doesFit = checkValPairs(checklist, keyList[key1], valList[key1], keyList[j], valList[j])
            end
        end
    end
end

-- Show wether the combination fits or not
ngx.say(doesFit)

On the second run, even from a new browser window, I get the following error:

*1 lua entry thread aborted: runtime error: /home/myname/code/workbench/src/handler.lua:3: attempt to call global 'loadCheckfile' (a nil value)

nginx.conf (only for developement, not the final one):

user root;

worker_processes 1;
daemon off;
error_log /dev/stdout warn;

events {
    worker_connections 32;
}

http {
    default_type text/html;
    access_log off;

    lua_package_path '/home/myname/code/workbench/src/?.lua;;';
    server {
       listen 80;

       location / {
            content_by_lua_file /home/myname/code/workbench/src/handler.lua;
        }
    }
}

loadCheckfile.lua:

local function fillChecklistTable(checklist, valueLine) 
    repeat
        firstValLength = string.find(valueLine,"=")
        firstVal = string.sub(valueLine, 1, firstValLength-1)

        valueLine = string.sub(valueLine, firstValLength+1)

        secondValLength = string.find(valueLine, ",")

        if secondValLength ~= nil then
            secondVal = string.sub(valueLine, 1, secondValLength-1)
        else
           secondVal = valueLine
        end

        if checklist[firstVal] == nil then
            checklist[firstVal] = {secondVal}
        else
            table.insert(checklist[firstVal], secondVal)
        end

        if secondValLength ~= nil then
            valueLine = string.sub(valueLine, secondValLength+1)
        else
            valueLine = nil
        end

     until valueLine == nil
end

checklist = {}

function loadCheckfile(checkfile)
    local values = io.open(checkfile)
    local valueLine = values:read()

    while valueLine ~= nil do
        fillChecklistTable(checklist, valueLine)
        valueLine = values:read()
    end
    return checklist
end

Anyone got an idea what this noob did wrong again? Thanks in advance!

Update:

handler.lua

checklist = {}

local checkFile = require("loadCheckfile")
local checkPairs = require("checkValPairs")

local checklist = checkFile.loadCheckfile("/home/myname/code/workbench/src/pw_list.txt")

local keyList = {}
local valList = {}

local args = ngx.req.get_uri_args()
for key, val in pairs(args) do
    table.insert(keyList, key)
    table.insert(valList, val)
end


ngx.say(unpack(keyList))
ngx.say(unpack(valList))


local key1

for i = 1, table.maxn(keyList) do
    if keyList[i] == "user" then
        key1 = i
        for j = 1, table.maxn(keyList) do
            if keyList[j] == "pass" then
                doesFit = checkValPairs(checklist, keyList[key1], valList[key1], keyList[j], valList[j])
            end
        end
    end
end

ngx.say(doesFit)

loadCheckfile.lua

module("loadCheckfile", package.seeall)

local function fillChecklistTable(checklist, valueLine) 
    repeat
        firstValLength = string.find(valueLine,"=")
        firstVal = string.sub(valueLine, 1, firstValLength-1)

        valueLine = string.sub(valueLine, firstValLength+1)

        secondValLength = string.find(valueLine, ",")

        if secondValLength ~= nil then
            secondVal = string.sub(valueLine, 1, secondValLength-1)
        else
            secondVal = valueLine
        end

        if checklist[firstVal] == nil then
            checklist[firstVal] = {secondVal}
        else
            table.insert(checklist[firstVal], secondVal)
        end

        if secondValLength ~= nil then
            valueLine = string.sub(valueLine, secondValLength+1)
        else
            valueLine = nil
        end

    until valueLine == nil
end

checklist = {}

function loadCheckfile.loadCheckfile(checkfile)
    local values = io.open(checkfile)
    local valueLine = values:read()

    while valueLine ~= nil do
        fillChecklistTable(checklist, valueLine)
        valueLine = values:read()
    end
    return checklist
end

According to this source I've put the module only into the loadCheckfile.lua and checkValPairs.lua. Yet even putting it into the handler.lua didn't work (just had to try).

Upvotes: 1

Views: 2136

Answers (3)

Mathias
Mathias

Reputation: 41

Attention

Please don't use this solution. While it does work it is not good. I'll leave it here to understand one of the answers.

Original answer:

The solution to my problem was to make the module global via the nginx.conf.

So I've inserted a init_by_lua_file in the configuration, calling a preloading lua file, that contained every function I need, providing this function on a global level.

The .conf:

user root;

worker_processes 1;
daemon off;  #used for developing purpose
error_log /dev/stdout warn; #as well for developing

events {
    worker_connections 32;
}


http {
    default_type text/html;
    access_log off;

    lua_package_path '/home/myname/code/workbench/src/?.lua;;'; 

    init_by_lua_file '/home/myname/code/workbench/src/preLoader.lua';

    server {
        listen 80;

        location / {
            content_by_lua_file /home/myname/code/workbench/src/handler.lua;
        }
    }
}

The new preLoader.lua:

require("loadCheckfile")
require("checkValPairs")
checklist = loadCheckfile("/home/myname/code/workbench/src/check.list")

And finally the handler.lua:

local keyList = {}
local valList = {}

-- Load GET arguments into tables
local args = ngx.req.get_uri_args()
for key, val in pairs(args) do
    table.insert(keyList, key)
    table.insert(valList, val)
end

-- show values in table (just for testing)
ngx.say(unpack(keyList))
ngx.say(unpack(valList))


local key1

-- search for keywords and look them up in the checklist
for i = 1, table.maxn(keyList) do
    if keyList[i] == "user" then
        key1 = i
        for j = 1, table.maxn(keyList) do
            if keyList[j] == "pass" then
                 doesFit = checkValPairs(checklist, keyList[key1], valList[key1], keyList[j], valList[j])
            end
        end
    end
end

-- Show wether the combination fits or not
ngx.say(doesFit)

Upvotes: 0

user3125367
user3125367

Reputation: 3000

Your solution should work, but there is something to know.

OpenResty creates a coroutine (Lua green thread) with fresh new global environment for each request, but require() only loads module once, never executing its main chunk again. So, all globals you set in these modules exist only during first request. Moreover, if your handler makes i/o, there is a window for second request to arrive and to steal its part of globals, so no requests will be completed. The accurate solution is to never set globals in your modules in OpenResty (and in ordinary Lua too, because spoiling _G is a bad idea in general), but to follow the standard module idiom instead:

-- mymod.lua

local M = { }

local function private() -- for internal use
    ...
end

function M.public() -- to be 'exported'
    ...
end

return M -- this will be returned from require


-- uses_mymod.lua

local mymod = require 'mymod' -- mymod is M from above

mymod.public()

This way module creates a table with functions instead of setting them as globals and returns it to require(). require() will return it each time called.

When you'll become tired of local function's visibility rules, introduce another local m = { } or whatever you like to name it, and store all privates there. After that becomes ugly in your eye, go for advanced topics like Lua environments (setfenv(), setmetatable()). If you don't want to go for details, put this line before local M = { } into each module:

setfenv(1, setmetatable({ }, { __index = getfenv(0) }))

All your globals will be local to that module, so you can avoid m (but not M, still required for 'exports').

Upvotes: 1

Tarun Lalwani
Tarun Lalwani

Reputation: 146630

Using lua_code_cache off is big performance issue as it is going to execute the code again and again. Try this

local checkFile = require("loadCheckfile")  
local checkPairs = require("checkValPairs")
local checklist = checkFile.loadCheckfile("/home/myname/code/workbench/src/check.lst")

Let me know if this works and I will add an explanation

Upvotes: 0

Related Questions