Skip to content

Instantly share code, notes, and snippets.

@silvpol
Last active May 13, 2021 07:02
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save silvpol/9d41590eb079a38e509a to your computer and use it in GitHub Desktop.
Save silvpol/9d41590eb079a38e509a to your computer and use it in GitHub Desktop.
---
--- Created Created by Swav Swiac on 23/07/2015.
---
--- Allows to run Redis Lua script in a debuggable environment resembling one provided by Redis
---
--- Usage:
---
--- local runner = require 'redis_runner'.connect(host, port)
---
--- local KEYS = {}
--- local ARGV = {}
--- local result = runner.runDebug('my_func.lua', KEYS, ARGV)
--- runner.dump(result)
---
-- default redis connection details
local default_host = "127.0.0.1"
local default_port = 6379
local P = {}
setmetatable(P, { __index = _G })
setfenv(1, P)
-- libs included in Redis
local table = require 'table'
local string = require 'string'
local math = require 'math'
local debug = require 'debug'
local struct = require 'struct'
local cjson = require 'cjson'
local cmsgpack = require 'cmsgpack'
local bit = require 'bit'
--local sha1hex = require 'redis.sha1hex'
local redis = require 'redis'
local run = function(debug, client, scriptfile, KEYS, ARGV)
-- Simulate Redis Lua environment by adding globals and functions
local globals = {
KEYS = KEYS,
ARGV = ARGV,
table = table,
string = string,
math = math,
debug = debug,
struct = struct,
cjson = cjson,
cmsgpack = cmsgpack,
bit = bit
}
globals.client = client
-- add lua-cjson and lua-cmsgpack
globals.cjson = cjson
globals.cmsgpack = cmsgpack
globals.redis = {
LOG_DEBUG = 'DEBUG',
LOG_VERBOSE = 'VERBOSE',
LOG_NOTICE = 'NOTICE',
LOG_WARNING = 'WARNING'
}
-- add redis.call
globals.redis.call = function(cmd, ...)
if debug then print(cmd .. ' ' .. ...) end
-- fetch correct command from redis-lua library
local command = client[string.lower(cmd)]
assert(command, 'Unknown command ' .. cmd)
-- execute it, first argument must be client object to simulate "client:" call
local result = command(client, ...)
-- convert result back to Redis style of {k1, v1, k2, v2 ...} if necessary
if type(result) == 'table' then
local fixed_result = {}
local i = 1;
for k, v in pairs(result) do
if type(k) ~= 'number' then
fixed_result[i] = k
fixed_result[i + 1] = v
i = i + 2
else
fixed_result[i] = v
i = i + 1
end
end
result = fixed_result
end
return result
end
-- add redis.log
globals.redis.log = function(level, message)
print('[' .. level .. '] ' .. message)
end
local env = setmetatable(globals, { __index = _G })
local err, result = assert(pcall(setfenv(assert(loadfile(scriptfile)), env)))
setmetatable(env, nil)
return result
end
-- prints dump of given variable
local dump = function(var)
if type(var) == 'table' then
require 'pl.pretty'.dump(var)
elseif type(var) == 'string' then
print('"' .. var .. '"')
else
print(tostring(var))
end
end
-- connect to Redis
function connect(host, port)
host = host or default_host
port = port or default_port
local client = redis.connect(host, port)
return {
-- run script without debug info
run = function(scriptfile, KEYS, ARGV)
return run(false, client, scriptfile, KEYS, ARGV)
end,
-- run script with extra debug info
runDebug = function(scriptfile, KEYS, ARGV)
return run(true, client, scriptfile, KEYS, ARGV)
end,
dump = dump
}
end
return P
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment