Redis lua script not working - lua

I have created a redis lua script to execute a command based on key data type :-
local keyType = redis.call("TYPE", KEYS[1])
if (keyType == "string")
then
return redis.call("GET",KEYS[1])
else
return nil
end
It is returning null every time I am executing it.Can any please help in correcting the script.

The response to redis.call returns as a table that looks like this: {"ok": "string"} (if the type is a string of course)
So in order to properly check, you should change your code to:
local keyType = redis.call("TYPE", KEYS[1]).ok
and the rest of the code will work fine.
The issue is this: the TYPE command is one of the few commands that return a "simple string" or "status" redis reply (see the redis protocol specs for the response types). In the redis lua documentation it's stated that:
Redis status reply -> Lua table with a single ok field containing the status
Which is what happened here.

Using [1] will also work.local keyType = redis.call("TYPE", KEYS[1]) return keyType[1]

Related

Use curried lua function as custom complete list in neovim

I'm trying to provide a curried lua function as method to call for autocomplete a command. However, it sometimes does nothing and sometimes fails with a memory segmentation error.
This is a minimal reproduction example:
Given this init.lua
vim.cmd(string.format([[set rtp=%s]], vim.fn.getcwd()))
local custom_complete = [[customlist,v:lua.require'split_later'.split_later('a b')]]
local options = { complete = custom_complete, desc = "Test to break", nargs = 1, force = true }
vim.api.nvim_create_user_command("Test", "echo <args>", options)
And this file called split_later under the correct lua/ subfolder:
local M = {}
function M.split_later(str)
print("called split")
return function()
return vim.fn.split(str)
end
end
return M
The idea is to have a generic utility that is able to produce auto-complete functions from lua, but it is not working as expected.
I found a workaround using a lookup table that stores the command name and then uses it, but I don't like it that much.

Struggling with calling lua functions from the command line

I have the following code:
dofile(arg[1])
function1 = arg[2]
argument = arg[3]
returned = _G[function1](argument)
print(returned)
It is designed to take three command-line arguments and run a function from a file.
So, i run the command lua libs.lua "printStuff.lua" "printStuff" "\"Hello, World\"", and i always end up with this:
"Hello, World"
nil
I don't understand why i always get "nil".
Here are the contents of printstuff.lua:
function printStuff(stuff)
print(stuff)
end
That is to be expected. What's going on here:
You're executing the file specified by the first argument, printstuff.lua, which will leave a function printStuff in the global table _G.
You're indexing the global table with the second argument, printStuff, obtaining that function
You're calling the function you just obtained with the third command line argument, "Hello World!", as parameter, which prints it, and storing the result of that in the global variable returned. The function printStuff doesn't return anything (there's no return in there, and even if there was, print doesn't return anything either), so you're assigning nil to returned.
You're printing returned, which is nil
Side note: I'd use the vararg ... instead of the arg table for improved readability:
local file, func, param = ...
dofile(file); print(func(param))
Why not simply...
-- xlua.lua
-- Example: lua xlua.lua os date "%H:%M:%S"
-- Or: lua xlua.lua _G print "Hello World"
-- Or: lua xlua.lua dofile /path/to/someusefull.lua "Arg for someusefull.lua"
local result = _G[arg[1]][arg[2]](arg[3])
-- 5. Only put out whats not nil
if (result ~= nil) then
print(result)
end

Nmap NSE script function is behaving differently if the argument is a hardcoded string or a variable containing said string

i'm trying to write a Nmap NSE DNS bruteforce script for a school work.
my problem is that when using the function : dns.query(dname,options)
where dname is a FQDN, the result is different is the argument is
1: A hardcoded string like this
local status, result = dns.query("www.domain.com", {dtype="A",retAll=true})
or 2: a variable made in the function match that concatenates two strings
local status, result = dns.query(domain, {dtype="A",retAll=true})
local function match(sub,host)
local domain = print(sub.."."..host.name)
local status, result = dns.query(domain, {dtype="A",retAll=true})
if status == "true" then
return domain
end
return ''
end
debug mode shows that the variable domain is indeed equal to the same value as the hardcoded string. But the behavior is different.
what could cause this sort of problem ?
docs for dns library : https://nmap.org/nsedoc/lib/dns.html

redis-rb multi only increment if key set

I want to store a count in redis. I want to increment the count only if the key exists. What am I doing wrong? exists is returning false and the incr is being executed.
key = "blah"
result = REDIS_DB.multi do
exists = REDIS_DB.exists(key)
REDIS_DB.incr(key) if exists
end
# result: [false, 1]
I am new to redis. I just read the redis transactions doc. From what I understand, the commands in multi should execute one after the other?
Rails 4.0.2, Redis 3.0.1, redis-rb (A Ruby client library for Redis)
As of redis 2.6 lua scripting is supported and it is transactional by definition so following code can be used as well.
redis_script = <<SCRIPT
local exists = redis.call('exists', KEYS[1])
if exists == 1 then
return redis.call('incr', KEYS[1])
end
SCRIPT
# returns incremented value if key exists otherwise nil
REDIS_DB.eval(redis_script, ['testkey'])
Read more about scripting and eval command
Coming to why incr in your actual code executed was because
Each REDIS_DB function call in multi block will return a Redis::Future object not an actual value, as redis-rb caches the commands in multi block. e.g.
REDIS_DB.multi do
return_value = REDIS_DB.exists('tesstt')
puts return_value.inspect
end
will print
<Redis::Future [:exists, "tesstt"]>
Now, If we got through the block in your example
exists = REDIS_DB.exists(key) # returns Redis::Future object
REDIS_DB.incr(key) if exists # evaluates to true as value of exists is an object
So where does result: [false, 1] comes from.
This is because REDIS_DB.multi after yielding your block (and caching the commands) finally converts it into redis query and sends it to redis which eventually runs it and returns the result. so your code is actually converted into following query.
MULTI
exists 'blah'
incr 'blah'
EXEC
and submitted together in a single call to redis which returns 0 for exists ( which redis-rb converts into boolean false) and 1 for incr.
Point to be noted is that this behavior is understandable as if you send each command individually to redis then redis itself will queue everything after MULTI and process it when call to exec is received
This might be what I was looking for:
result = REDIS_DB.watch(key) do
if REDIS_DB.exists(key)
REDIS_DB.incr(key)
else
REDIS_DB.unwatch
end
end

Why is 'name' nil for debug.getinfo(1)

I'm trying to put together a lua testing framework that lets you know the function that had the problem, but when I switched from loadstring to _G, (I switched so my test harness could see the results of the function call) my functions started using 'nil' for the function name
Why can _G not detect the name of the current function in the following code? Also, how can I get the return results from loadstring (ie the 'false' from the blah call) or set the function name when using _G (ie. Tell the lua interpreter what the function name should be)?
function run_test(one, two)
if one ~= two then
print(debug.getinfo(2).name..' Failed')
end
end
function blah()
run_test(false, true)
return false
end
local fname = 'blah'
local status, result = pcall(_G[fname]) -- Outputs 'nil'; result is 'false'
local status, result = pcall(loadstring(fname..'()')) -- Outputs 'blah', result is 'nil'
The main thing I need is a way to call a function using a string of the function name, be able to see the function name inside the call (for test failures to point to the function that failed, like fname = 'blah' in the code above) and be able to get the return value
local fname = 'blah'
status, result = pcall(??Call fname somehow??)
assert(status)
assert(not result)
--stdout should be "blah Failed"
This is a limitation of the heuristics used by Lua to provide names for functions.
In Lua, all functions are anonymous. A given function can be the value of several variables: global, local, and table fields. The Lua debug system tries to find a reasonable name for a value based on where it came from by looking into the bytecode being executed.
Consider the simpler example
blah()
pcall(blah)
In the first call, the debug system sees that the function being called comes from the global blah and debug.getinfo(1).name gives the expected result, blah.
In the second call, the debug system sees that the function being called comes from the first argument to pcall but it does not look further to see where that argument came from, and debug.getinfo(1).name gives nil.
The same thing happens when you call _G[name](). All the debug system sees is a field of a table and the name of the field is too far off.
Try adding print(debug.traceback()) as the first line of blah to see another take on this explanation.

Resources