From a355440c01d5ece456bda9c5a4f302ec82929dff Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Mon, 1 Jun 2020 15:44:44 +0100 Subject: prosodyctl, util.prosodyctl.shell: `prosodyctl shell` - a client to access the prosodyctl admin shell --- util/prosodyctl/shell.lua | 125 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 util/prosodyctl/shell.lua (limited to 'util/prosodyctl/shell.lua') diff --git a/util/prosodyctl/shell.lua b/util/prosodyctl/shell.lua new file mode 100644 index 00000000..0b84eaca --- /dev/null +++ b/util/prosodyctl/shell.lua @@ -0,0 +1,125 @@ +local have_unix, unix = pcall(require, "socket.unix"); + +if not have_unix or type(unix) ~= "table" then + print("** LuaSocket unix socket support not available or incompatible, ensure your"); + print("** version is up to date."); + os.exit(1); +end + +local server = require "net.server"; +local st = require "util.stanza"; + +local have_readline, readline = pcall(require, "readline"); + +local adminstream = require "util.adminstream"; + +if have_readline then + readline.set_readline_name("prosody"); +end + +local function read_line() + if have_readline then + return readline.readline("prosody> "); + else + io.write("prosody> "); + return io.read("*line"); + end +end + +local function send_line(client, line) + client.send(st.stanza("repl-line"):text(line)); +end + +local function repl(client) + local line = read_line(); + if not line or line == "quit" or line == "exit" or line == "bye" then + if not line then + print(""); + end + os.exit(); + end + send_line(client, line); +end + +local function connection(socket_path, listeners) + local conn, sock; + + return { + connect = function () + if sock or conn then + return nil, "already connected"; + end + sock = unix.stream(); + sock:settimeout(0); + local ok, err = sock:connect(socket_path); + if not ok then + return nil, err; + end + conn = server.wrapclient(sock, nil, nil, listeners, "*a"); + return true; + end; + disconnect = function () + if conn then + conn:close(); + conn = nil; + end + if sock then + sock:close(); + sock = nil; + end + return true; + end; + }; +end + +local function printbanner() + print([[ + ____ \ / _ + | _ \ _ __ ___ ___ _-_ __| |_ _ + | |_) | '__/ _ \/ __|/ _ \ / _` | | | | + | __/| | | (_) \__ \ |_| | (_| | |_| | + |_| |_| \___/|___/\___/ \__,_|\__, | + A study in simplicity |___/ + +]]); + print("Welcome to the Prosody administration console. For a list of commands, type: help"); + print("You may find more help on using this console in our online documentation at "); + print("https://prosody.im/doc/console\n"); +end + +local function start(arg) --luacheck: ignore 212/arg + local client = adminstream.client(); + + client.events.add_handler("connected", function () + if not arg.quiet then + printbanner(); + end + repl(client); + end); + + client.events.add_handler("disconnected", function () + print("--- session closed ---"); + os.exit(); + end); + + client.events.add_handler("received", function (stanza) + if stanza.name == "repl-result" then + local result_prefix = stanza.attr.type == "error" and "!" or "|"; + print(result_prefix.." "..stanza:get_text()); + repl(client); + end + end); + + local conn = connection("data/prosody.sock", client.listeners); + local ok, err = conn:connect(); + if not ok then + print("** Unable to connect to server - is it running? Is mod_admin_shell enabled?"); + print("** Connection error: "..err); + os.exit(1); + end + server.loop(); +end + +return { + start = start; +}; -- cgit v1.2.3