diff --git a/src/lua/console.lua b/src/lua/console.lua index 5ff1c2ed75a394c474d45177ea3d9da02457e84e..3bc0ff68ca172fef163c66f4d4cea0a43ba597ef 100644 --- a/src/lua/console.lua +++ b/src/lua/console.lua @@ -2,6 +2,7 @@ local internal = require('console') local formatter = require('yaml') +local session = require('session') local function format(status, ...) -- When storing a nil in a Lua table, there is no way to @@ -25,7 +26,7 @@ local function format(status, ...) return formatter.encode(res) end -local function eval(line, ...) +local function local_eval(self, line, ...) -- -- Attempt to append 'return ' before the chunk: if the chunk is -- an expression, this pushes results of the expression onto the @@ -42,8 +43,50 @@ local function eval(line, ...) return format(pcall(fun, ...)) end +local function eval(line) + return local_eval(nil, line) +end + +local local_mt = { + __index = { + eval = local_eval; + close = function() end; + prompt = function() return 'tarantool' end; + } +} + +local function remote_eval(self, line, ...) + -- + -- call remote 'console.eval' function using 'dostring' and return result + -- + local status, res = pcall(self.conn.call, self.conn, "dostring", + "return require('console').eval(...)", line) + if not status then + -- remote request failed + return format(status, res) + end + -- return formatted output from remote + return res[1][0] +end + +local function remote_close(self) + pcall(self.conn.close, self.conn) -- ignore errors +end + +local function remote_prompt(self) + return string.format("%s:%s", self.conn.host, self.conn.port) +end + +local remote_mt = { + __index = { + eval = remote_eval; + close = remote_close; + prompt = remote_prompt; + } +} + local function read(host) - local delim = require('session').delimiter() + local delim = session.delimiter() local linenum = 0 local buf = "" while true do @@ -62,23 +105,45 @@ local function read(host) end local function repl() - local host = "tarantool" + if session.storage.console ~= nil then + return -- REPL is already enabled + end + session.storage.console = {} + local handlers = {} + table.insert(handlers, setmetatable({}, local_mt)) + session.storage.console.handlers = handlers local line - while true do + while #handlers > 0 do + local handler = handlers[#handlers] -- read - local line = read(host) + local line = read(handler:prompt()) if line == nil then - break + -- remove handler + io.write("\n") + handler:close() + table.remove(handlers) + else + -- eval + local out = handler:eval(line) + -- print + io.write(out) + internal.add_history(line) end - -- eval - local out = eval(line) - -- print - io.write(out) - internal.add_history(line) end end +local function connect(...) + if not session.storage.console then + error("console.connect() works only in interactive mode") + end + local conn = box.net.box.new(...) + conn:ping() -- test connection + table.insert(session.storage.console.handlers, setmetatable( + { conn = conn}, remote_mt)) +end + return { repl = repl; eval = eval; + connect = connect; }