This slightly changes table_print() output format.
table_print() output is not intended for machine consumption,
use krprint.serialize_lua() or JSON for that purpose.
Output from table_print is now a valid Lua expression
if the input contains only serializable data types
(number, string, bool, nil, table), which is nice for copy&pasting.
Functions etc. are also pretty-printed but cannot be deserialized.
Numbers are pretty-printed as well so their precision is reduced (as
compared to krprint.serialize_lua).
end
local function test_text_single_command()
- local expect = "this is test"
- ctrl_sock_txt:xwrite(string.format('"%s"\n', expect), nil, timeout)
- data = ctrl_sock_txt:xread(#expect + 2, nil, timeout)
- same(data, expect .. '\n\n',
+ local string = "this is test"
+ local input = string.format("'%s'\n", string)
+ local expect = input
+ ctrl_sock_txt:xwrite(input, nil, timeout)
+ data = ctrl_sock_txt:xread(#expect, nil, timeout)
+ same(data, expect,
'text mode returns output in expected format')
end
ctrl_sock_bin:xwrite('id\n', nil, timeout)
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.pid..'\n', 'binary mode returns output in expected format')
+ same(data, tostring(worker.pid),
+ 'binary mode returns number in expected format')
ctrl_sock_bin:xwrite('worker.p', nil, timeout)
worker.sleep(0.01)
ctrl_sock_bin:xwrite('id\nworker.id\n', nil, timeout)
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.pid..'\n', 'binary mode returns output in expected format')
+ same(data, tostring(worker.pid),
+ 'binary mode returns number in expected format')
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.id..'\n', 'binary mode returns output in expected format')
+ same(data, string.format("'%s'", worker.id),
+ 'binary mode returns string in expected format')
ctrl_sock_bin:xwrite('worker.pid', nil, timeout)
worker.sleep(0.01)
ctrl_sock_bin:xwrite('\n', nil, timeout)
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.pid..'\n', 'binary mode returns output in expected format')
+ same(data, tostring(worker.pid),
+ 'binary mode returns output in expected format')
ctrl_sock_bin:xwrite('worker.pid', nil, timeout)
worker.sleep(0.01)
ctrl_sock_bin:xwrite('\n', nil, timeout)
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.pid..'\n', 'binary mode returns output in expected format')
+ same(data, tostring(worker.pid),
+ 'binary mode returns number in expected format')
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.id..'\n', 'binary mode returns output in expected format')
+ same(data, string.format("'%s'", worker.id),
+ 'binary mode returns string in expected format')
ctrl_sock_bin:xwrite('worker.pid\nworker.pid\nworker.pid\nworker.pid\n', nil, timeout)
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.pid..'\n', 'binary mode returns output in expected format')
+ same(data, tostring(worker.pid),
+ 'binary mode returns number in expected format')
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.pid..'\n', 'binary mode returns output in expected format')
+ same(data, tostring(worker.pid),
+ 'binary mode returns number in expected format')
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.pid..'\n', 'binary mode returns output in expected format')
+ same(data, tostring(worker.pid),
+ 'binary mode returns number in expected format')
len = binary_xread_len(ctrl_sock_bin)
data = ctrl_sock_bin:xread(len, nil, timeout)
- same(data, worker.pid..'\n', 'binary mode returns output in expected format')
+ same(data, tostring(worker.pid),
+ 'binary mode returns number in expected format')
end
local function test_close_incomplete_cmd()
end
-- Pretty printing
-
-local function funcsign(f)
--- thanks to AnandA777 from StackOverflow! Function funcsign is adapted version of
--- https://stackoverflow.com/questions/51095022/inspect-function-signature-in-lua-5-1
- assert(type(f) == 'function', "bad argument #1 to 'funcsign' (function expected)")
- local debuginfo = debug.getinfo(f)
- if debuginfo.what == 'C' then -- names N/A
- return '(?)'
- end
-
- local func_args = {}
- pcall(function()
- local oldhook
- local delay = 2
- local function hook()
- delay = delay - 1
- if delay == 0 then -- call this only for the introspected function
- -- stack depth 2 is the introspected function
- for i = 1, debuginfo.nparams do
- local k = debug.getlocal(2, i)
- table.insert(func_args, k)
- end
- if debuginfo.isvararg then
- table.insert(func_args, "...")
- end
- debug.sethook(oldhook)
- error('aborting the call to introspected function')
- end
- end
- oldhook = debug.sethook(hook, "c") -- invoke hook() on function call
- f(unpack({})) -- huh?
- end)
- return "(" .. table.concat(func_args, ", ") .. ")"
-end
-
-function table_print(tt, indent, done)
- done = done or {}
- indent = indent or 0
- local result = ""
- -- Ordered for-iterator for tables with tostring-able keys.
- local function ordered_iter(unordered_tt)
- local keys = {}
- for k in pairs(unordered_tt) do
- table.insert(keys, k)
- end
- table.sort(keys,
- function (a, b)
- if type(a) ~= type(b) then
- return type(a) < type(b)
- end
- if type(a) == 'number' then
- return a < b
- else
- return tostring(a) < tostring(b)
- end
- end)
- local i = 0
- return function()
- i = i + 1
- if keys[i] ~= nil then
- return keys[i], unordered_tt[keys[i]]
- end
- end
- end
- -- Convert to printable string (escape unprintable)
- local function printable(value)
- value = tostring(value)
- local bytes = {}
- for i = 1, #value do
- local c = string.byte(value, i)
- if c >= 0x20 and c < 0x7f then table.insert(bytes, string.char(c))
- else table.insert(bytes, '\\'..tostring(c))
- end
- if i > 80 then table.insert(bytes, '...') break end
- end
- return table.concat(bytes)
- end
- if type(tt) == "table" then
- for key, value in ordered_iter(tt) do
- result = result .. string.rep (" ", indent)
- if type (value) == "table" and not done [value] then
- done [value] = true
- result = result .. string.format("[%s] => {\n", printable (key))
- result = result .. table_print (value, indent + 4, done)
- result = result .. string.rep (" ", indent)
- result = result .. "}\n"
- elseif type (value) == "function" then
- result = result .. string.format("[%s] => function %s%s: %s\n",
- tostring(key), tostring(key), funcsign(value),
- string.sub(tostring(value), 11))
- else
- result = result .. string.format("[%s] => %s\n",
- tostring (key), printable(value))
- end
- end
- else -- not a table
- local tt_str
- if type(tt) == "function" then
- tt_str = string.format("function%s: %s\n", funcsign(tt),
- string.sub(tostring(tt), 11))
- else
- tt_str = tostring(tt)
- end
- result = result .. tt_str .. "\n"
- end
- return result
-end
+table_print = require('krprint').pprint
-- This extends the worker module to allow asynchronous execution of functions and nonblocking I/O.
-- The current implementation combines cqueues for Lua interface, and event.socket() in order to not
end
end
result_count = result_count + 1
+ -- return value is output from eval_cmd
+ -- i.e. string including "quotes" and Lua escaping in between
+ assert(type(ret) == 'string', 'map() protocol error, '
+ .. 'string not retured by follower')
+ assert(#ret >= 2 and
+ string.sub(ret, 1, 1) == "'"
+ and string.sub(ret, -1, -1) == "'",
+ 'map() protocol error, value returned by follower does '
+ .. 'not look like a string')
+ -- deserialize string: remove "quotes" and de-escape bytes
+ ret = krprint.deserialize_lua(ret)
if format == 'luaobj' then
+ -- ret should be table with xpcall results serialized into string
ret = krprint.deserialize_lua(ret)
- -- ret is now table with xpcall results
assert(type(ret) == 'table', 'map() protocol error, '
.. 'table with results not retured by follower')
if (ret.n ~= 2) then
end
-- drop wrapper table and return only the actual return value
ret = retval
- else
- assert(type(ret) == 'string', 'map() protocol error, '
- .. 'string not retured by follower')
end
results[result_count] = ret
::continue::
* `DNS Flag Day 2020 <https://dnsflagday.net/2020/>`_ is now effective and Knot Resolver uses
maximum size of UDP answer to 1232 bytes. Please double-check your firewall,
it has to allow DNS traffic on UDP and **also TCP** port 53.
-
+* Human readable output in interactive mode and from :ref:`control-sockets` was improved and
+ as consequence slightly changed its format. Users who need machine readable output for scripts
+ should use Lua function ``tojson()`` to convert Lua values into standard JSON format instead
+ of attempting to parse the human readable output.
+ For example API call ``tojson(cache.stats())\n`` will return JSON string with ``cache.stats()``
+ results represented as dictionary.
+ Function ``tojson()`` is available in all resolver versions >= 1.0.0.
Configuration file
------------------
same(option('REORDER_RR', false), false, 'generic option call')
boom(option, {'REORDER_RR', 'potato'}, 'generic option call argument check')
boom(option, {'MARS_VACATION', false}, 'generic option check name')
- same(table_print('crabdiary'), 'crabdiary\n', 'table print works')
- same(table_print({fakepizza=1}), '[fakepizza] => 1\n', 'table print works on tables')
+ same(table_print('crabdiary'), "'crabdiary'", 'table print works')
+ same(table_print({fakepizza=1}), "{\n ['fakepizza'] = 1,\n}", 'table print works on tables')
end
-- test if dns library functions work