1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
local config = require "prosody.core.configmanager";
local server = require "prosody.net.server";
local st = require "prosody.util.stanza";
local path = require "prosody.util.paths";
local parse_args = require "prosody.util.argparse".parse;
local unpack = table.unpack or _G.unpack;
local tc = require "prosody.util.termcolours";
local isatty = require "prosody.util.pposix".isatty;
local term_width = require"prosody.util.human.io".term_width;
local have_readline, readline = pcall(require, "readline");
local adminstream = require "prosody.util.adminstream";
if have_readline then
readline.set_readline_name("prosody");
readline.set_options({
histfile = path.join(prosody.paths.data, ".shell_history");
ignoredups = true;
});
end
local function read_line(prompt_string)
if have_readline then
return readline.readline(prompt_string);
else
io.write(prompt_string);
return io.read("*line");
end
end
local function send_line(client, line)
client.send(st.stanza("repl-input", { width = term_width() }):text(line));
end
local function repl(client)
local line = read_line(client.prompt_string or "prosody> ");
if not line or line == "quit" or line == "exit" or line == "bye" then
if not line then
print("");
end
if have_readline then
readline.save_history();
end
os.exit(0, true);
end
send_line(client, line);
end
local function printbanner()
local banner = config.get("*", "console_banner");
if banner then return print(banner); end
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();
local opts, err, where = parse_args(arg);
local ttyout = isatty(io.stdout);
if not opts then
if err == "param-not-found" then
print("Unknown command-line option: "..tostring(where));
elseif err == "missing-value" then
print("Expected a value to follow command-line option: "..where);
end
os.exit(1);
end
if arg[1] then
if arg[2] then
-- prosodyctl shell module reload foo bar.com --> module:reload("foo", "bar.com")
arg[1] = string.format("%s:%s("..string.rep("%q", #arg-2,", ")..")", unpack(arg));
end
client.events.add_handler("connected", function()
client.send(st.stanza("repl-input"):text(arg[1]));
return true;
end, 1);
local errors = 0; -- TODO This is weird, but works for now.
client.events.add_handler("received", function(stanza)
if stanza.name == "repl-output" or stanza.name == "repl-result" then
local dest = io.stdout;
if stanza.attr.type == "error" then
errors = errors + 1;
dest = io.stderr;
end
if stanza.attr.eol == "0" then
dest:write(stanza:get_text());
else
dest:write(stanza:get_text(), "\n");
end
end
if stanza.name == "repl-result" then
os.exit(errors);
end
return true;
end, 1);
end
client.events.add_handler("connected", function ()
if not opts.quiet then
printbanner();
end
repl(client);
end);
client.events.add_handler("disconnected", function ()
print("--- session closed ---");
os.exit(0, true);
end);
client.events.add_handler("received", function (stanza)
if stanza.name == "repl-output" or stanza.name == "repl-result" then
local result_prefix = stanza.attr.type == "error" and "!" or "|";
local out = result_prefix.." "..stanza:get_text();
if ttyout and stanza.attr.type == "error" then
out = tc.getstring(tc.getstyle("red"), out);
end
print(out);
end
if stanza.name == "repl-result" then
repl(client);
end
end);
client.prompt_string = config.get("*", "admin_shell_prompt");
local socket_path = path.resolve_relative_path(prosody.paths.data, opts.socket or config.get("*", "admin_socket") or "prosody.sock");
local conn = adminstream.connection(socket_path, client.listeners);
local ok, err = conn:connect();
if not ok then
if err == "no unix socket support" then
print("** LuaSocket unix socket support not available or incompatible, ensure your");
print("** version is up to date.");
else
print("** Unable to connect to server - is it running? Is mod_admin_shell enabled?");
print("** Connection error: "..err);
end
os.exit(1);
end
server.loop();
end
return {
shell = start;
};
|