Mercurial > irccd
comparison irccdctl/cli.cpp @ 527:a88796ed040a
Irccdctl: switch to Boost.Asio, closes #697
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 16 Nov 2017 22:45:12 +0100 |
parents | e03521cf207b |
children | 9daccaeedcce |
comparison
equal
deleted
inserted
replaced
526:5df38b4fbc55 | 527:a88796ed040a |
---|---|
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
17 */ | 17 */ |
18 | 18 |
19 #include <cassert> | 19 #include <boost/system/system_error.hpp> |
20 #include <iostream> | 20 |
21 #include <sstream> | 21 #include <irccd/errors.hpp> |
22 | 22 #include <irccd/json_util.hpp> |
23 #include <boost/timer/timer.hpp> | 23 #include <irccd/options.hpp> |
24 | 24 #include <irccd/string_util.hpp> |
25 #include <json.hpp> | 25 |
26 #include <irccd/ctl/controller.hpp> | |
26 | 27 |
27 #include "cli.hpp" | 28 #include "cli.hpp" |
28 #include "irccdctl.hpp" | |
29 #include "json_util.hpp" | |
30 #include "logger.hpp" | |
31 #include "options.hpp" | |
32 #include "net_util.hpp" | |
33 #include "string_util.hpp" | |
34 | |
35 using namespace std::string_literals; | |
36 | 29 |
37 namespace irccd { | 30 namespace irccd { |
38 | 31 |
39 /* | 32 namespace ctl { |
40 * Cli. | 33 |
41 * ------------------------------------------------------------------ | 34 void cli::recv_response(ctl::controller& ctl, nlohmann::json req, handler_t handler) |
42 */ | 35 { |
43 | 36 ctl.recv([&ctl, req, handler, this] (auto code, auto message) { |
44 void Cli::check(const nlohmann::json &response) | 37 if (code) |
45 { | 38 throw boost::system::system_error(code); |
46 if (!json_util::get_bool(response, "status", false)) { | 39 |
47 auto error = json_util::get_string(response, "error"); | 40 auto c = json_util::to_string(message["command"]); |
48 | 41 |
49 if (error.empty()) | 42 if (c != req["command"].get<std::string>()) { |
50 throw std::runtime_error("command failed with an unknown error"); | 43 recv_response(ctl, std::move(req), std::move(handler)); |
51 | 44 return; |
52 throw std::runtime_error(error); | 45 } |
53 } | 46 |
54 } | 47 if (message["error"].is_number_integer()) |
55 | 48 throw boost::system::system_error(static_cast<network_error>(message["error"].template get<int>())); |
56 nlohmann::json Cli::request(Irccdctl &irccdctl, nlohmann::json args) | 49 if (message["error"].is_string()) |
57 { | 50 throw std::runtime_error(message["error"].template get<std::string>()); |
58 auto msg = nlohmann::json(); | 51 |
59 | 52 if (handler) |
60 if (!args.is_object()) | 53 handler(std::move(message)); |
61 args = nlohmann::json::object(); | 54 }); |
62 | 55 } |
63 args.push_back({"command", m_name}); | 56 |
64 irccdctl.client().request(args); | 57 void cli::request(ctl::controller& ctl, nlohmann::json req, handler_t handler) |
65 | 58 { |
66 auto id = irccdctl.client().onMessage.connect([&] (auto input) { | 59 ctl.send(req, [&ctl, req, handler, this] (auto code, auto) { |
67 msg = std::move(input); | 60 if (code) |
68 }); | 61 throw boost::system::system_error(code); |
69 | 62 |
70 try { | 63 recv_response(ctl, std::move(req), std::move(handler)); |
71 boost::timer::cpu_timer timer; | 64 }); |
72 | 65 } |
73 while (irccdctl.client().isConnected() && !msg.is_object() && timer.elapsed().wall / 1000000LL < 3000) | 66 |
74 net_util::poll(3000 - timer.elapsed().wall / 1000000LL, irccdctl); | 67 /* |
75 } catch (const std::exception &) { | 68 * plugin_info_cli. |
76 irccdctl.client().onMessage.disconnect(id); | 69 * ------------------------------------------------------------------ |
77 throw; | 70 */ |
78 } | 71 |
79 | 72 void plugin_config_cli::set(ctl::controller& ctl, const std::vector<std::string>&args) |
80 irccdctl.client().onMessage.disconnect(id); | 73 { |
81 | 74 request(ctl, { |
82 if (!msg.is_object()) | |
83 throw std::runtime_error("no response received"); | |
84 if (json_util::get_string(msg, "command") != m_name) | |
85 throw std::runtime_error("unexpected command result received"); | |
86 | |
87 check(msg); | |
88 | |
89 return msg; | |
90 } | |
91 | |
92 void Cli::call(Irccdctl &irccdctl, nlohmann::json args) | |
93 { | |
94 check(request(irccdctl, args)); | |
95 } | |
96 | |
97 namespace cli { | |
98 | |
99 /* | |
100 * PluginConfigCli. | |
101 * ------------------------------------------------------------------ | |
102 */ | |
103 | |
104 void PluginConfigCli::set(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
105 { | |
106 check(request(irccdctl, nlohmann::json::object({ | |
107 { "plugin", args[0] }, | 75 { "plugin", args[0] }, |
108 { "variable", args[1] }, | 76 { "variable", args[1] }, |
109 { "value", args[2] } | 77 { "value", args[2] } |
110 }))); | 78 }); |
111 } | 79 } |
112 | 80 |
113 void PluginConfigCli::get(Irccdctl &irccdctl, const std::vector<std::string> &args) | 81 void plugin_config_cli::get(ctl::controller& ctl, const std::vector<std::string>& args) |
114 { | 82 { |
115 auto result = request(irccdctl, nlohmann::json::object({ | 83 auto json = nlohmann::json::object({ |
116 { "plugin", args[0] }, | 84 { "plugin", args[0] }, |
117 { "variable", args[1] } | 85 { "variable", args[1] } |
118 })); | 86 }); |
119 | 87 |
120 check(result); | 88 request(ctl, std::move(json), [args] (auto result) { |
121 | 89 if (result["variables"].is_object()) |
122 if (result["variables"].is_object()) | 90 std::cout << json_util::pretty(result["variables"][args[1]]) << std::endl; |
123 std::cout << json_util::pretty(result["variables"][args[1]]) << std::endl; | 91 }); |
124 } | 92 } |
125 | 93 |
126 void PluginConfigCli::getall(Irccdctl &irccdctl, const std::vector<std::string> &args) | 94 void plugin_config_cli::getall(ctl::controller& ctl, const std::vector<std::string> &args) |
127 { | 95 { |
128 auto result = request(irccdctl, nlohmann::json::object({{ "plugin", args[0] }})); | 96 request(ctl, {{ "plugin", args[0] }}, [] (auto result) { |
129 | 97 auto variables = result["variables"]; |
130 check(result); | 98 |
131 | 99 for (auto v = variables.begin(); v != variables.end(); ++v) |
132 auto variables = result["variables"]; | 100 std::cout << std::setw(16) << std::left << v.key() << " : " << json_util::pretty(v.value()) << std::endl; |
133 | 101 }); |
134 for (auto v = variables.begin(); v != variables.end(); ++v) | 102 } |
135 std::cout << std::setw(16) << std::left << v.key() << " : " << json_util::pretty(v.value()) << std::endl; | 103 |
136 } | 104 std::string plugin_config_cli::name() const |
137 | 105 { |
138 PluginConfigCli::PluginConfigCli() | 106 return "plugin-config"; |
139 : Cli("plugin-config", | 107 } |
140 "configure a plugin", | 108 |
141 "plugin-config plugin [variable] [value]", | 109 void plugin_config_cli::exec(ctl::controller& ctl, const std::vector<std::string> &args) |
142 "Get or set a plugin configuration variable.\n\n" | |
143 "If both variable and value are provided, sets the plugin configuration " | |
144 "to the\nrespective variable name and value.\n\n" | |
145 "If only variable is specified, shows its current value. Otherwise, list " | |
146 "all\nvariables and their values.\n\n" | |
147 "Examples:\n" | |
148 "\tirccdctl plugin-config ask") | |
149 { | |
150 } | |
151 | |
152 void PluginConfigCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
153 { | 110 { |
154 switch (args.size()) { | 111 switch (args.size()) { |
155 case 3: | 112 case 3: |
156 set(irccdctl, args); | 113 set(ctl, args); |
157 break; | 114 break; |
158 case 2: | 115 case 2: |
159 get(irccdctl, args); | 116 get(ctl, args); |
160 break; | 117 break; |
161 case 1: | 118 case 1: |
162 getall(irccdctl, args); | 119 getall(ctl, args); |
163 break; | 120 break; |
164 default: | 121 default: |
165 throw std::invalid_argument("plugin-config requires at least 1 argument"); | 122 throw std::invalid_argument("plugin-config requires at least 1 argument"); |
166 } | 123 } |
167 } | 124 } |
168 | 125 |
169 /* | 126 /* |
170 * PluginInfoCli. | 127 * plugin_info_cli. |
171 * ------------------------------------------------------------------ | 128 * ------------------------------------------------------------------ |
172 */ | 129 */ |
173 | 130 |
174 PluginInfoCli::PluginInfoCli() | 131 std::string plugin_info_cli::name() const |
175 : Cli("plugin-info", | 132 { |
176 "get plugin information", | 133 return "plugin-info"; |
177 "plugin-info plugin", | 134 } |
178 "Get plugin information.\n\n" | 135 |
179 "Example:\n" | 136 void plugin_info_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
180 "\tirccdctl plugin-info ask" | |
181 ) | |
182 { | |
183 } | |
184 | |
185 void PluginInfoCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
186 { | 137 { |
187 if (args.size() < 1) | 138 if (args.size() < 1) |
188 throw std::invalid_argument("plugin-info requires 1 argument"); | 139 throw std::invalid_argument("plugin-info requires 1 argument"); |
189 | 140 |
190 auto result = request(irccdctl, {{ "plugin", args[0] }}); | 141 request(ctl, {{ "plugin", args[0] }}, [] (auto result) { |
191 | 142 std::cout << std::boolalpha; |
192 std::cout << std::boolalpha; | 143 std::cout << "Author : " << json_util::get_string(result, "author") << std::endl; |
193 std::cout << "Author : " << json_util::get_string(result, "author") << std::endl; | 144 std::cout << "License : " << json_util::get_string(result, "license") << std::endl; |
194 std::cout << "License : " << json_util::get_string(result, "license") << std::endl; | 145 std::cout << "Summary : " << json_util::get_string(result, "summary") << std::endl; |
195 std::cout << "Summary : " << json_util::get_string(result, "summary") << std::endl; | 146 std::cout << "Version : " << json_util::get_string(result, "version") << std::endl; |
196 std::cout << "Version : " << json_util::get_string(result, "version") << std::endl; | 147 }); |
197 } | 148 } |
198 | 149 |
199 /* | 150 /* |
200 * PluginListCli. | 151 * plugin_list_cli. |
201 * ------------------------------------------------------------------ | 152 * ------------------------------------------------------------------ |
202 */ | 153 */ |
203 | 154 |
204 PluginListCli::PluginListCli() | 155 std::string plugin_list_cli::name() const |
205 : Cli("plugin-list", | 156 { |
206 "list loaded plugins", | 157 return "plugin-list"; |
207 "plugin-list", | 158 } |
208 "Get the list of all loaded plugins.\n\n" | 159 |
209 "Example:\n" | 160 void plugin_list_cli::exec(ctl::controller& ctl, const std::vector<std::string>&) |
210 "\tirccdctl plugin-list") | 161 { |
211 { | 162 request(ctl, {{ "command", "plugin-list" }}, [] (auto result) { |
212 } | 163 for (const auto &value : result["list"]) |
213 | 164 if (value.is_string()) |
214 void PluginListCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &) | 165 std::cout << value.template get<std::string>() << std::endl; |
215 { | 166 }); |
216 auto result = request(irccdctl); | 167 } |
217 | 168 |
218 for (const auto &value : result["list"]) | 169 /* |
219 if (value.is_string()) | 170 * plugin_load_cli. |
220 std::cout << value.get<std::string>() << std::endl; | 171 * ------------------------------------------------------------------ |
221 } | 172 */ |
222 | 173 |
223 /* | 174 std::string plugin_load_cli::name() const |
224 * PluginLoadCli. | 175 { |
225 * ------------------------------------------------------------------ | 176 return "plugin-load"; |
226 */ | 177 } |
227 | 178 |
228 PluginLoadCli::PluginLoadCli() | 179 void plugin_load_cli::exec(ctl::controller& ctl, const std::vector<std::string> &args) |
229 : Cli("plugin-load", | |
230 "load a plugin", | |
231 "plugin-load logger", | |
232 "Load a plugin into the irccd instance.\n\n" | |
233 "Example:\n" | |
234 "\tirccdctl plugin-load logger") | |
235 { | |
236 } | |
237 | |
238 void PluginLoadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
239 { | 180 { |
240 if (args.size() < 1) | 181 if (args.size() < 1) |
241 throw std::invalid_argument("plugin-load requires 1 argument"); | 182 throw std::invalid_argument("plugin-load requires 1 argument"); |
242 | 183 |
243 check(request(irccdctl, {{"plugin", args[0]}})); | 184 request(ctl, {{ "plugin", args[0] }}); |
244 } | 185 } |
245 | 186 |
246 /* | 187 /* |
247 * PluginReloadCli. | 188 * plugin_reload_cli. |
248 * ------------------------------------------------------------------ | 189 * ------------------------------------------------------------------ |
249 */ | 190 */ |
250 | 191 |
251 PluginReloadCli::PluginReloadCli() | 192 std::string plugin_reload_cli::name() const |
252 : Cli("plugin-reload", | 193 { |
253 "reload a plugin", | 194 return "plugin-reload"; |
254 "plugin-reload plugin", | 195 } |
255 "Reload a plugin by calling the appropriate onReload event, the plugin is not\n" | 196 |
256 "unloaded and must be already loaded.\n\n" | 197 void plugin_reload_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
257 "Example:\n" | |
258 "\tirccdctl plugin-reload logger") | |
259 { | |
260 } | |
261 | |
262 void PluginReloadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
263 { | 198 { |
264 if (args.size() < 1) | 199 if (args.size() < 1) |
265 throw std::invalid_argument("plugin-reload requires 1 argument"); | 200 throw std::invalid_argument("plugin-reload requires 1 argument"); |
266 | 201 |
267 check(request(irccdctl, {{ "plugin", args[0] }})); | 202 request(ctl, {{ "plugin", args[0] }}); |
268 } | 203 } |
269 | 204 |
270 /* | 205 /* |
271 * PluginUnloadCli. | 206 * plugin_unload_cli. |
272 * ------------------------------------------------------------------ | 207 * ------------------------------------------------------------------ |
273 */ | 208 */ |
274 | 209 |
275 PluginUnloadCli::PluginUnloadCli() | 210 std::string plugin_unload_cli::name() const |
276 : Cli("plugin-unload", | 211 { |
277 "unload a plugin", | 212 return "plugin-unload"; |
278 "plugin-unload plugin", | 213 } |
279 "Unload a loaded plugin from the irccd instance.\n\n" | 214 |
280 "Example:\n" | 215 void plugin_unload_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
281 "\tirccdctl plugin-unload logger") | |
282 { | |
283 } | |
284 | |
285 void PluginUnloadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
286 { | 216 { |
287 if (args.size() < 1) | 217 if (args.size() < 1) |
288 throw std::invalid_argument("plugin-unload requires 1 argument"); | 218 throw std::invalid_argument("plugin-unload requires 1 argument"); |
289 | 219 |
290 check(request(irccdctl, {{ "plugin", args[0] }})); | 220 request(ctl, {{ "plugin", args[0] }}); |
291 } | 221 } |
292 | 222 |
293 /* | 223 /* |
294 * ServerChannelCli. | 224 * server_channel_cli. |
295 * ------------------------------------------------------------------ | 225 * ------------------------------------------------------------------ |
296 */ | 226 */ |
297 | 227 |
298 ServerChannelMode::ServerChannelMode() | 228 std::string server_channel_mode_cli::name() const |
299 : Cli("server-cmode", | 229 { |
300 "change channel mode", | 230 return "server-cmode"; |
301 "server-cmode server channel mode", | 231 } |
302 "Change the mode of the specified channel.\n\n" | 232 |
303 "Example:\n" | 233 void server_channel_mode_cli::exec(ctl::controller& ctl, const std::vector<std::string> &args) |
304 "\tirccdctl server-cmode freenode #staff +t") | |
305 { | |
306 } | |
307 | |
308 void ServerChannelMode::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
309 { | 234 { |
310 if (args.size() < 3) | 235 if (args.size() < 3) |
311 throw std::invalid_argument("server-cmode requires 3 arguments"); | 236 throw std::invalid_argument("server-cmode requires 3 arguments"); |
312 | 237 |
313 check(request(irccdctl, { | 238 request(ctl, { |
314 { "command", "server-cmode" }, | 239 { "command", "server-cmode" }, |
315 { "server", args[0] }, | 240 { "server", args[0] }, |
316 { "channel", args[1] }, | 241 { "channel", args[1] }, |
317 { "mode", args[2] } | 242 { "mode", args[2] } |
318 })); | 243 }); |
319 } | 244 } |
320 | 245 |
321 /* | 246 /* |
322 * ServerChannelNoticeCli. | 247 * server_channel_notice_cli. |
323 * ------------------------------------------------------------------ | 248 * ------------------------------------------------------------------ |
324 */ | 249 */ |
325 | 250 |
326 ServerChannelNoticeCli::ServerChannelNoticeCli() | 251 std::string server_channel_notice_cli::name() const |
327 : Cli("server-cnotice", | 252 { |
328 "send a channel notice", | 253 return "server-cnotice"; |
329 "server-cnotice server channel message", | 254 } |
330 "Send a notice to a public channel. This is a notice that everyone on the channel\n" | 255 |
331 "will receive.\n\n" | 256 void server_channel_notice_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
332 "Example:\n" | |
333 "\tirccdctl server-cnotice freenode #staff \"Don't flood!\"") | |
334 { | |
335 } | |
336 | |
337 void ServerChannelNoticeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
338 { | 257 { |
339 if (args.size() < 3) | 258 if (args.size() < 3) |
340 throw std::invalid_argument("server-cnotice requires 3 arguments"); | 259 throw std::invalid_argument("server-cnotice requires 3 arguments"); |
341 | 260 |
342 check(request(irccdctl, { | 261 request(ctl, { |
343 { "command", "server-cnotice" }, | 262 { "command", "server-cnotice" }, |
344 { "server", args[0] }, | 263 { "server", args[0] }, |
345 { "channel", args[1] }, | 264 { "channel", args[1] }, |
346 { "message", args[2] } | 265 { "message", args[2] } |
347 })); | 266 }); |
348 } | 267 } |
349 | 268 |
350 /* | 269 /* |
351 * ServerConnectCli. | 270 * server_connect_cli. |
352 * ------------------------------------------------------------------ | 271 * ------------------------------------------------------------------ |
353 */ | 272 */ |
354 | 273 |
355 namespace { | 274 namespace { |
356 | 275 |
374 return option::read(args, options); | 293 return option::read(args, options); |
375 } | 294 } |
376 | 295 |
377 } // !namespace | 296 } // !namespace |
378 | 297 |
379 ServerConnectCli::ServerConnectCli() | 298 std::string server_connect_cli::name() const |
380 : Cli("server-connect", | 299 { |
381 "add a server", | 300 return "server-connect"; |
382 "server-connect [options] id host [port]", | 301 } |
383 "Connect to a new IRC server.\n\n" | 302 |
384 "Available options:\n" | 303 void server_connect_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
385 " -c, --command\t\tspecify the command char\n" | |
386 " -n, --nickname\tspecify a nickname\n" | |
387 " -r, --realname\tspecify a real name\n" | |
388 " -S, --ssl-verify\tverify SSL\n" | |
389 " -s, --ssl\t\tconnect using SSL\n" | |
390 " -u, --username\tspecify a user name\n\n" | |
391 "Example:\n" | |
392 "\tirccdctl server-connect -n jean example irc.example.org\n" | |
393 "\tirccdctl server-connect --ssl example irc.example.org 6697") | |
394 { | |
395 } | |
396 | |
397 void ServerConnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
398 { | 304 { |
399 std::vector<std::string> copy(args); | 305 std::vector<std::string> copy(args); |
400 | 306 |
401 option::result result = parse(copy); | 307 option::result result = parse(copy); |
402 option::result::const_iterator it; | 308 option::result::const_iterator it; |
425 if ((it = result.find("-r")) != result.end() || (it = result.find("--realname")) != result.end()) | 331 if ((it = result.find("-r")) != result.end() || (it = result.find("--realname")) != result.end()) |
426 object["realname"] = it->second; | 332 object["realname"] = it->second; |
427 if ((it = result.find("-u")) != result.end() || (it = result.find("--username")) != result.end()) | 333 if ((it = result.find("-u")) != result.end() || (it = result.find("--username")) != result.end()) |
428 object["username"] = it->second; | 334 object["username"] = it->second; |
429 | 335 |
430 check(request(irccdctl, object)); | 336 request(ctl, object); |
431 } | 337 } |
432 | 338 |
433 /* | 339 /* |
434 * ServerDisconnectCli. | 340 * server_disconnect_cli. |
435 * ------------------------------------------------------------------ | 341 * ------------------------------------------------------------------ |
436 */ | 342 */ |
437 | 343 |
438 ServerDisconnectCli::ServerDisconnectCli() | 344 std::string server_disconnect_cli::name() const |
439 : Cli("server-disconnect", | 345 { |
440 "disconnect server", | 346 return "server-disconnect"; |
441 "server-disconnect [server]", | 347 } |
442 "Disconnect from a server.\n\n" | 348 |
443 "If server is not specified, irccd disconnects all servers.\n\n" | 349 void server_disconnect_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
444 "Example:\n" | |
445 "\tirccdctl server-disconnect localhost") | |
446 { | |
447 } | |
448 | |
449 void ServerDisconnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
450 { | 350 { |
451 auto object = nlohmann::json::object({ | 351 auto object = nlohmann::json::object({ |
452 { "command", "server-disconnect" } | 352 { "command", "server-disconnect" } |
453 }); | 353 }); |
454 | 354 |
455 if (args.size() > 0) | 355 if (args.size() > 0) |
456 object["server"] = args[0]; | 356 object["server"] = args[0]; |
457 | 357 |
458 check(request(irccdctl, object)); | 358 request(ctl, object); |
459 } | 359 } |
460 | 360 |
461 /* | 361 /* |
462 * ServerInfoCli. | 362 * server_info_cli. |
463 * ------------------------------------------------------------------ | 363 * ------------------------------------------------------------------ |
464 */ | 364 */ |
465 | 365 |
466 ServerInfoCli::ServerInfoCli() | 366 std::string server_info_cli::name() const |
467 : Cli("server-info", | 367 { |
468 "get server information", | 368 return "server-info"; |
469 "server-info server", | 369 } |
470 "Get information about a server.\n\n" | 370 |
471 "Example:\n" | 371 void server_info_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
472 "\tirccdctl server-info freenode") | |
473 { | |
474 } | |
475 | |
476 void ServerInfoCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
477 { | 372 { |
478 if (args.size() < 1) | 373 if (args.size() < 1) |
479 throw std::invalid_argument("server-info requires 1 argument"); | 374 throw std::invalid_argument("server-info requires 1 argument"); |
480 | 375 |
481 auto result = request(irccdctl, { | 376 auto json = nlohmann::json::object({ |
482 { "command", "server-info" }, | 377 { "command", "server-info" }, |
483 { "server", args[0] } | 378 { "server", args[0] } |
484 }); | 379 }); |
485 | 380 |
486 check(result); | 381 request(ctl, std::move(json), [] (auto result) { |
487 | 382 std::cout << std::boolalpha; |
488 std::cout << std::boolalpha; | 383 std::cout << "Name : " << json_util::pretty(result["name"]) << std::endl; |
489 std::cout << "Name : " << json_util::pretty(result["name"]) << std::endl; | 384 std::cout << "Host : " << json_util::pretty(result["host"]) << std::endl; |
490 std::cout << "Host : " << json_util::pretty(result["host"]) << std::endl; | 385 std::cout << "Port : " << json_util::pretty(result["port"]) << std::endl; |
491 std::cout << "Port : " << json_util::pretty(result["port"]) << std::endl; | 386 std::cout << "Ipv6 : " << json_util::pretty(result["ipv6"]) << std::endl; |
492 std::cout << "Ipv6 : " << json_util::pretty(result["ipv6"]) << std::endl; | 387 std::cout << "SSL : " << json_util::pretty(result["ssl"]) << std::endl; |
493 std::cout << "SSL : " << json_util::pretty(result["ssl"]) << std::endl; | 388 std::cout << "SSL verified : " << json_util::pretty(result["sslVerify"]) << std::endl; |
494 std::cout << "SSL verified : " << json_util::pretty(result["sslVerify"]) << std::endl; | 389 std::cout << "Channels : "; |
495 std::cout << "Channels : "; | 390 |
496 | 391 for (const auto &v : result["channels"]) |
497 for (const auto &v : result["channels"]) | 392 if (v.is_string()) |
498 if (v.is_string()) | 393 std::cout << v.template get<std::string>() << " "; |
499 std::cout << v.get<std::string>() << " "; | 394 |
500 | 395 std::cout << std::endl; |
501 std::cout << std::endl; | 396 |
502 | 397 std::cout << "Nickname : " << json_util::pretty(result["nickname"]) << std::endl; |
503 std::cout << "Nickname : " << json_util::pretty(result["nickname"]) << std::endl; | 398 std::cout << "User name : " << json_util::pretty(result["username"]) << std::endl; |
504 std::cout << "User name : " << json_util::pretty(result["username"]) << std::endl; | 399 std::cout << "Real name : " << json_util::pretty(result["realname"]) << std::endl; |
505 std::cout << "Real name : " << json_util::pretty(result["realname"]) << std::endl; | 400 }); |
506 } | 401 } |
507 | 402 |
508 /* | 403 /* |
509 * ServerInviteCli. | 404 * server_invite_cli. |
510 * ------------------------------------------------------------------ | 405 * ------------------------------------------------------------------ |
511 */ | 406 */ |
512 | 407 |
513 ServerInviteCli::ServerInviteCli() | 408 std::string server_invite_cli::name() const |
514 : Cli("server-invite", | 409 { |
515 "invite someone", | 410 return "server-invite"; |
516 "server-invite server nickname channel", | 411 } |
517 "Invite the specified target on the channel.\n\n" | 412 |
518 "Example:\n" | 413 void server_invite_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
519 "\tirccdctl server-invite freenode xorg62 #staff") | |
520 { | |
521 } | |
522 | |
523 void ServerInviteCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
524 { | 414 { |
525 if (args.size() < 3) | 415 if (args.size() < 3) |
526 throw std::invalid_argument("server-invite requires 3 arguments"); | 416 throw std::invalid_argument("server-invite requires 3 arguments"); |
527 | 417 |
528 check(request(irccdctl, { | 418 request(ctl, { |
529 { "command", "server-invite" }, | 419 { "command", "server-invite" }, |
530 { "server", args[0] }, | 420 { "server", args[0] }, |
531 { "target", args[1] }, | 421 { "target", args[1] }, |
532 { "channel", args[2] } | 422 { "channel", args[2] } |
533 })); | 423 }); |
534 } | 424 } |
535 | 425 |
536 /* | 426 /* |
537 * ServerJoinCli. | 427 * server_join_cli. |
538 * ------------------------------------------------------------------ | 428 * ------------------------------------------------------------------ |
539 */ | 429 */ |
540 | 430 |
541 ServerJoinCli::ServerJoinCli() | 431 std::string server_join_cli::name() const |
542 : Cli("server-join", | 432 { |
543 "join a channel", | 433 return "server-join"; |
544 "server-join server channel [password]", | 434 } |
545 "Join the specified channel, the password is optional.\n\n" | 435 |
546 "Example:\n" | 436 void server_join_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
547 "\tirccdctl server-join freenode #test\n" | |
548 "\tirccdctl server-join freenode #private-club secret") | |
549 { | |
550 } | |
551 | |
552 void ServerJoinCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
553 { | 437 { |
554 if (args.size() < 2) | 438 if (args.size() < 2) |
555 throw std::invalid_argument("server-join requires at least 2 arguments"); | 439 throw std::invalid_argument("server-join requires at least 2 arguments"); |
556 | 440 |
557 auto object = nlohmann::json::object({ | 441 auto object = nlohmann::json::object({ |
560 }); | 444 }); |
561 | 445 |
562 if (args.size() == 3) | 446 if (args.size() == 3) |
563 object["password"] = args[2]; | 447 object["password"] = args[2]; |
564 | 448 |
565 check(request(irccdctl, object)); | 449 request(ctl, object); |
566 } | 450 } |
567 | 451 |
568 /* | 452 /* |
569 * ServerKickCli. | 453 * server_kick_cli. |
570 * ------------------------------------------------------------------ | 454 * ------------------------------------------------------------------ |
571 */ | 455 */ |
572 | 456 |
573 ServerKickCli::ServerKickCli() | 457 std::string server_kick_cli::name() const |
574 : Cli("server-kick", | 458 { |
575 "kick someone from a channel", | 459 return "server-kick"; |
576 "server-kick server target channel [reason]", | 460 } |
577 "Kick the specified target from the channel, the reason is optional.\n\n" | 461 |
578 "Example:\n" | 462 void server_kick_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
579 "\tirccdctl server-kick freenode jean #staff \"Stop flooding\"") | |
580 { | |
581 } | |
582 | |
583 void ServerKickCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
584 { | 463 { |
585 if (args.size() < 3) | 464 if (args.size() < 3) |
586 throw std::invalid_argument("server-kick requires at least 3 arguments "); | 465 throw std::invalid_argument("server-kick requires at least 3 arguments "); |
587 | 466 |
588 auto object = nlohmann::json::object({ | 467 auto object = nlohmann::json::object({ |
592 }); | 471 }); |
593 | 472 |
594 if (args.size() == 4) | 473 if (args.size() == 4) |
595 object["reason"] = args[3]; | 474 object["reason"] = args[3]; |
596 | 475 |
597 check(request(irccdctl, object)); | 476 request(ctl, object); |
598 } | 477 } |
599 | 478 |
600 /* | 479 /* |
601 * ServerListCli. | 480 * server_list_cli. |
602 * ------------------------------------------------------------------ | 481 * ------------------------------------------------------------------ |
603 */ | 482 */ |
604 | 483 |
605 ServerListCli::ServerListCli() | 484 std::string server_list_cli::name() const |
606 : Cli("server-list", | 485 { |
607 "get list of servers", | 486 return "server-list"; |
608 "server-list", | 487 } |
609 "Get the list of all connected servers.\n\n" | 488 |
610 "Example:\n" | 489 void server_list_cli::exec(ctl::controller& ctl, const std::vector<std::string>&) |
611 "\tirccdctl server-list") | 490 { |
612 { | 491 request(ctl, {{ "command", "server-list" }}, [] (auto result) { |
613 } | 492 for (const auto &n : result["list"]) |
614 | 493 if (n.is_string()) |
615 void ServerListCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &) | 494 std::cout << n.template get<std::string>() << std::endl; |
616 { | 495 }); |
617 auto response = request(irccdctl); | 496 } |
618 | 497 |
619 check(response); | 498 /* |
620 | 499 * server_me_cli. |
621 for (const auto &n : response["list"]) | 500 * ------------------------------------------------------------------ |
622 if (n.is_string()) | 501 */ |
623 std::cout << n.get<std::string>() << std::endl; | 502 |
624 } | 503 std::string server_me_cli::name() const |
625 | 504 { |
626 /* | 505 return "server-me"; |
627 * ServerMeCli. | 506 } |
628 * ------------------------------------------------------------------ | 507 |
629 */ | 508 void server_me_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
630 | |
631 ServerMeCli::ServerMeCli() | |
632 : Cli("server-me", | |
633 "send an action emote", | |
634 "server-me server target message", | |
635 "Send an action emote.\n\n" | |
636 "Example:\n" | |
637 "\tirccdctl server-me freenode #staff \"going back soon\"") | |
638 { | |
639 } | |
640 | |
641 void ServerMeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
642 { | 509 { |
643 if (args.size() < 3) | 510 if (args.size() < 3) |
644 throw std::runtime_error("server-me requires 3 arguments"); | 511 throw std::runtime_error("server-me requires 3 arguments"); |
645 | 512 |
646 check(request(irccdctl, { | 513 request(ctl, { |
647 { "server", args[0] }, | 514 { "server", args[0] }, |
648 { "target", args[1] }, | 515 { "target", args[1] }, |
649 { "message", args[2] } | 516 { "message", args[2] } |
650 })); | 517 }); |
651 } | 518 } |
652 | 519 |
653 /* | 520 /* |
654 * ServerMessageCli. | 521 * server_message_cli. |
655 * ------------------------------------------------------------------ | 522 * ------------------------------------------------------------------ |
656 */ | 523 */ |
657 | 524 |
658 ServerMessageCli::ServerMessageCli() | 525 std::string server_message_cli::name() const |
659 : Cli("server-message", | 526 { |
660 "send a message", | 527 return "server-message"; |
661 "server-message server target message", | 528 } |
662 "Send a message to the specified target or channel.\n\n" | 529 |
663 "Example:\n" | 530 void server_message_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
664 "\tirccdctl server-message freenode #staff \"Hello from irccd\"") | |
665 { | |
666 } | |
667 | |
668 void ServerMessageCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
669 { | 531 { |
670 if (args.size() < 3) | 532 if (args.size() < 3) |
671 throw std::invalid_argument("server-message requires 3 arguments"); | 533 throw std::invalid_argument("server-message requires 3 arguments"); |
672 | 534 |
673 check(request(irccdctl, { | 535 request(ctl, { |
674 { "server", args[0] }, | 536 { "server", args[0] }, |
675 { "target", args[1] }, | 537 { "target", args[1] }, |
676 { "message", args[2] } | 538 { "message", args[2] } |
677 })); | 539 }); |
678 } | 540 } |
679 | 541 |
680 /* | 542 /* |
681 * ServerModeCli. | 543 * server_mode_cli. |
682 * ------------------------------------------------------------------ | 544 * ------------------------------------------------------------------ |
683 */ | 545 */ |
684 | 546 |
685 ServerModeCli::ServerModeCli() | 547 std::string server_mode_cli::name() const |
686 : Cli("server-mode", | 548 { |
687 "the the user mode", | 549 return "server-mode"; |
688 "server-mode server mode", | 550 } |
689 "Set the irccd's user mode.\n\n" | 551 |
690 "Example:\n" | 552 void server_mode_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
691 "\tirccdctl server-mode +i") | |
692 { | |
693 } | |
694 | |
695 void ServerModeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
696 { | 553 { |
697 if (args.size() < 2) | 554 if (args.size() < 2) |
698 throw std::invalid_argument("server-mode requires 2 arguments"); | 555 throw std::invalid_argument("server-mode requires 2 arguments"); |
699 | 556 |
700 check(request(irccdctl, { | 557 request(ctl, { |
701 { "server", args[0] }, | 558 { "server", args[0] }, |
702 { "mode", args[1] } | 559 { "mode", args[1] } |
703 })); | 560 }); |
704 } | 561 } |
705 | 562 |
706 /* | 563 /* |
707 * ServerNickCli. | 564 * server_nick_cli. |
708 * ------------------------------------------------------------------ | 565 * ------------------------------------------------------------------ |
709 */ | 566 */ |
710 | 567 |
711 ServerNickCli::ServerNickCli() | 568 std::string server_nick_cli::name() const |
712 : Cli("server-nick", | 569 { |
713 "change your nickname", | 570 return "server-nick"; |
714 "server-nick server nickname", | 571 } |
715 "Change irccd's nickname.\n\n" | 572 |
716 "Example:\n" | 573 void server_nick_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
717 "\tirccdctl server-nick freenode david") | |
718 { | |
719 } | |
720 | |
721 void ServerNickCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
722 { | 574 { |
723 if (args.size() < 2) | 575 if (args.size() < 2) |
724 throw std::invalid_argument("server-nick requires 2 arguments"); | 576 throw std::invalid_argument("server-nick requires 2 arguments"); |
725 | 577 |
726 check(request(irccdctl, { | 578 request(ctl, { |
727 { "server", args[0] }, | 579 { "server", args[0] }, |
728 { "nickname", args[1] } | 580 { "nickname", args[1] } |
729 })); | 581 }); |
730 } | 582 } |
731 | 583 |
732 /* | 584 /* |
733 * ServerNoticeCli. | 585 * server_notice_cli. |
734 * ------------------------------------------------------------------ | 586 * ------------------------------------------------------------------ |
735 */ | 587 */ |
736 | 588 |
737 ServerNoticeCli::ServerNoticeCli() | 589 std::string server_notice_cli::name() const |
738 : Cli("server-notice", | 590 { |
739 "send a private notice", | 591 return "server-notice"; |
740 "server-notice server target message", | 592 } |
741 "Send a private notice to the specified target.\n\n" | 593 |
742 "Example:\n" | 594 void server_notice_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
743 "\tirccdctl server-notice freenode jean \"I know you are here.\"") | |
744 { | |
745 } | |
746 | |
747 void ServerNoticeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
748 { | 595 { |
749 if (args.size() < 3) | 596 if (args.size() < 3) |
750 throw std::invalid_argument("server-notice requires 3 arguments"); | 597 throw std::invalid_argument("server-notice requires 3 arguments"); |
751 | 598 |
752 check(request(irccdctl, { | 599 request(ctl, { |
753 { "server", args[0] }, | 600 { "server", args[0] }, |
754 { "target", args[1] }, | 601 { "target", args[1] }, |
755 { "message", args[2] } | 602 { "message", args[2] } |
756 })); | 603 }); |
757 } | 604 } |
758 | 605 |
759 /* | 606 /* |
760 * ServerPartCli. | 607 * server_part_cli. |
761 * ------------------------------------------------------------------ | 608 * ------------------------------------------------------------------ |
762 */ | 609 */ |
763 | 610 |
764 ServerPartCli::ServerPartCli() | 611 std::string server_part_cli::name() const |
765 : Cli("server-part", | 612 { |
766 "leave a channel", | 613 return "server-part"; |
767 "server-part server channel [reason]", | 614 } |
768 "Leave the specified channel, the reason is optional.\n\n" | 615 |
769 "Not all IRC servers support giving a reason to leave a channel, do not specify\n" | 616 void server_part_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
770 "it if this is a concern.\n\n" | |
771 "Example:\n" | |
772 "\tirccdctl server-part freenode #staff\n" | |
773 "\tirccdctl server-part freenode #botwar \"too noisy\"") | |
774 { | |
775 } | |
776 | |
777 void ServerPartCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
778 { | 617 { |
779 if (args.size() < 2) | 618 if (args.size() < 2) |
780 throw std::invalid_argument("server-part requires at least 2 arguments"); | 619 throw std::invalid_argument("server-part requires at least 2 arguments"); |
781 | 620 |
782 auto object = nlohmann::json::object({ | 621 auto object = nlohmann::json::object({ |
785 }); | 624 }); |
786 | 625 |
787 if (args.size() >= 3) | 626 if (args.size() >= 3) |
788 object["reason"] = args[2]; | 627 object["reason"] = args[2]; |
789 | 628 |
790 check(request(irccdctl, object)); | 629 request(ctl, object); |
791 } | 630 } |
792 | 631 |
793 /* | 632 /* |
794 * ServerReconnectCli. | 633 * server_reconnect_cli. |
795 * ------------------------------------------------------------------ | 634 * ------------------------------------------------------------------ |
796 */ | 635 */ |
797 | 636 |
798 ServerReconnectCli::ServerReconnectCli() | 637 std::string server_reconnect_cli::name() const |
799 : Cli("server-reconnect", | 638 { |
800 "force reconnection of a server", | 639 return "server-reconnect"; |
801 "server-reconnect [server]", | 640 } |
802 "Force reconnection of one or all servers.\n\n" | 641 |
803 "If server is not specified, all servers will try to reconnect.\n\n" | 642 void server_reconnect_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
804 "Example:\n" | |
805 "\tirccdctl server-reconnect\n" | |
806 "\tirccdctl server-reconnect wanadoo") | |
807 { | |
808 } | |
809 | |
810 void ServerReconnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
811 { | 643 { |
812 auto object = nlohmann::json::object({ | 644 auto object = nlohmann::json::object({ |
813 { "command", "server-reconnect" } | 645 { "command", "server-reconnect" } |
814 }); | 646 }); |
815 | 647 |
816 if (args.size() >= 1) | 648 if (args.size() >= 1) |
817 object["server"] = args[0]; | 649 object["server"] = args[0]; |
818 | 650 |
819 check(request(irccdctl, object)); | 651 request(ctl, object); |
820 } | 652 } |
821 | 653 |
822 /* | 654 /* |
823 * ServerTopicCli. | 655 * server_topic_cli. |
824 * ------------------------------------------------------------------ | 656 * ------------------------------------------------------------------ |
825 */ | 657 */ |
826 | 658 |
827 ServerTopicCli::ServerTopicCli() | 659 std::string server_topic_cli::name() const |
828 : Cli("server-topic", | 660 { |
829 "change channel topic", | 661 return "server-topic"; |
830 "server-topic server channel topic", | 662 } |
831 "Change the topic of the specified channel.\n\n" | 663 |
832 "Example:\n" | 664 void server_topic_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
833 "\tirccdctl server-topic freenode #wmfs \"This is the best channel\"") | |
834 { | |
835 } | |
836 | |
837 void ServerTopicCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
838 { | 665 { |
839 if (args.size() < 3) | 666 if (args.size() < 3) |
840 throw std::invalid_argument("server-topic requires 3 arguments"); | 667 throw std::invalid_argument("server-topic requires 3 arguments"); |
841 | 668 |
842 check(request(irccdctl, { | 669 request(ctl, { |
843 { "server", args[0] }, | 670 { "server", args[0] }, |
844 { "channel", args[1] }, | 671 { "channel", args[1] }, |
845 { "topic", args[2] } | 672 { "topic", args[2] } |
846 })); | 673 }); |
847 } | 674 } |
848 | 675 |
849 /* | 676 /* |
850 * RuleAddCli. | 677 * rule_add_cli. |
851 * ------------------------------------------------------------------ | 678 * ------------------------------------------------------------------ |
852 */ | 679 */ |
853 | 680 |
854 RuleAddCli::RuleAddCli() | 681 std::string rule_add_cli::name() const |
855 : Cli("rule-add", | 682 { |
856 "add a new rule", | 683 return "rule-add"; |
857 "rule-add [options] accept|drop", | 684 } |
858 "Add a new rule to irccd.\n\n" | 685 |
859 "If no index is specified, the rule is added to the end.\n\n" | 686 void rule_add_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
860 "Available options:\n" | |
861 " -c, --add-channel\t\tmatch a channel\n" | |
862 " -e, --add-event\t\tmatch an event\n" | |
863 " -i, --index\t\t\trule position\n" | |
864 " -p, --add-plugin\t\tmatch a plugin\n" | |
865 " -s, --add-server\t\tmatch a server\n\n" | |
866 "Example:\n" | |
867 "\tirccdctl rule-add -p hangman drop\n" | |
868 "\tirccdctl rule-add -s localhost -c #games -p hangman accept") | |
869 { | |
870 } | |
871 | |
872 void RuleAddCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
873 { | 687 { |
874 static const option::options options{ | 688 static const option::options options{ |
875 { "-c", true }, | 689 { "-c", true }, |
876 { "--add-channel", true }, | 690 { "--add-channel", true }, |
877 { "-e", true }, | 691 { "-e", true }, |
916 if (result.count("--index") > 0) | 730 if (result.count("--index") > 0) |
917 json["index"] = string_util::to_number<unsigned>(result.find("--index")->second); | 731 json["index"] = string_util::to_number<unsigned>(result.find("--index")->second); |
918 | 732 |
919 // And action. | 733 // And action. |
920 if (copy[0] != "accept" && copy[0] != "drop") | 734 if (copy[0] != "accept" && copy[0] != "drop") |
921 throw std::runtime_error("invalid action '"s + copy[0] + "'"); | 735 throw std::runtime_error(string_util::sprintf("invalid action '%s'", copy[0])); |
922 | 736 |
923 json["action"] = copy[0]; | 737 json["action"] = copy[0]; |
924 | 738 |
925 check(request(irccdctl, json)); | 739 request(ctl, json); |
926 } | 740 } |
927 | 741 |
928 /* | 742 /* |
929 * RuleEditCli. | 743 * rule_edit_cli. |
930 * ------------------------------------------------------------------ | 744 * ------------------------------------------------------------------ |
931 */ | 745 */ |
932 | 746 |
933 RuleEditCli::RuleEditCli() | 747 std::string rule_edit_cli::name() const |
934 : Cli("rule-edit", | 748 { |
935 "edit an existing rule", | 749 return "rule-edit"; |
936 "rule-edit [options] index", | 750 } |
937 "Edit an existing rule in irccd.\n\n" | 751 |
938 "All options can be specified multiple times.\n\n" | 752 void rule_edit_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
939 "Available options:\n" | |
940 " -a, --action\t\t\tset action\n" | |
941 " -c, --add-channel\t\tmatch a channel\n" | |
942 " -C, --remove-channel\t\tremove a channel\n" | |
943 " -e, --add-event\t\tmatch an event\n" | |
944 " -E, --remove-event\t\tremove an event\n" | |
945 " -p, --add-plugin\t\tmatch a plugin\n" | |
946 " -P, --add-plugin\t\tremove a plugin\n" | |
947 " -s, --add-server\t\tmatch a server\n" | |
948 " -S, --remove-server\t\tremove a server\n\n" | |
949 "Example:\n" | |
950 "\tirccdctl rule-edit -p hangman 0\n" | |
951 "\tirccdctl rule-edit -S localhost -c #games -p hangman 1") | |
952 { | |
953 } | |
954 | |
955 void RuleEditCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
956 { | 753 { |
957 static const option::options options{ | 754 static const option::options options{ |
958 { "-a", true }, | 755 { "-a", true }, |
959 { "--action", true }, | 756 { "--action", true }, |
960 { "-c", true }, | 757 { "-c", true }, |
1016 } | 813 } |
1017 | 814 |
1018 // Index. | 815 // Index. |
1019 json["index"] = string_util::to_number<unsigned>(copy[0]); | 816 json["index"] = string_util::to_number<unsigned>(copy[0]); |
1020 | 817 |
1021 check(request(irccdctl, json)); | 818 request(ctl, json); |
1022 } | 819 } |
1023 | 820 |
1024 /* | 821 /* |
1025 * RuleListCli. | 822 * rule_list_cli. |
1026 * ------------------------------------------------------------------ | 823 * ------------------------------------------------------------------ |
1027 */ | 824 */ |
1028 | 825 |
1029 namespace { | 826 namespace { |
1030 | 827 |
1031 void showRule(const nlohmann::json& json, int index) | 828 void show_rule(const nlohmann::json& json, int index) |
1032 { | 829 { |
1033 assert(json.is_object()); | 830 assert(json.is_object()); |
1034 | 831 |
1035 auto unjoin = [] (auto array) { | 832 auto unjoin = [] (auto array) { |
1036 std::ostringstream oss; | 833 std::ostringstream oss; |
1060 std::cout << std::endl; | 857 std::cout << std::endl; |
1061 } | 858 } |
1062 | 859 |
1063 } // !namespace | 860 } // !namespace |
1064 | 861 |
1065 RuleListCli::RuleListCli() | 862 std::string rule_list_cli::name() const |
1066 : Cli("rule-list", | 863 { |
1067 "list all rules", | 864 return "rule-list"; |
1068 "rule-list", | 865 } |
1069 "List all rules.\n\n" | 866 |
1070 "Example:\n" | 867 void rule_list_cli::exec(ctl::controller& ctl, const std::vector<std::string>&) |
1071 "\tirccdctl rule-list") | 868 { |
1072 { | 869 request(ctl, {{ "command", "rule-list" }}, [] (auto result) { |
1073 } | 870 auto pos = 0; |
1074 | 871 |
1075 void RuleListCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &) | 872 for (const auto& obj : result["list"]) { |
1076 { | 873 if (obj.is_object()) |
1077 auto response = request(irccdctl); | 874 show_rule(obj, pos++); |
1078 auto pos = 0; | 875 } |
1079 | 876 }); |
1080 check(response); | 877 } |
1081 | 878 |
1082 for (const auto &obj : response["list"]) { | 879 /* |
1083 if (!obj.is_object()) | 880 * rule_info_cli. |
1084 continue; | 881 * ------------------------------------------------------------------ |
1085 | 882 */ |
1086 showRule(obj, pos++); | 883 |
1087 } | 884 std::string rule_info_cli::name() const |
1088 } | 885 { |
1089 | 886 return "rule-info"; |
1090 /* | 887 } |
1091 * RuleInfoCli. | 888 |
1092 * ------------------------------------------------------------------ | 889 void rule_info_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
1093 */ | |
1094 | |
1095 RuleInfoCli::RuleInfoCli() | |
1096 : Cli("rule-info", | |
1097 "show a rule", | |
1098 "rule-info index", | |
1099 "Show a rule.\n\n" | |
1100 "Example:\n" | |
1101 "\tirccdctl rule-info 0\n" | |
1102 "\tirccdctl rule-info 1") | |
1103 { | |
1104 } | |
1105 | |
1106 void RuleInfoCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
1107 { | 890 { |
1108 if (args.size() < 1) | 891 if (args.size() < 1) |
1109 throw std::invalid_argument("rule-info requires 1 argument"); | 892 throw std::invalid_argument("rule-info requires 1 argument"); |
1110 | 893 |
1111 int index = 0; | 894 int index = 0; |
1114 index = std::stoi(args[0]); | 897 index = std::stoi(args[0]); |
1115 } catch (...) { | 898 } catch (...) { |
1116 throw std::invalid_argument("invalid number '" + args[0] + "'"); | 899 throw std::invalid_argument("invalid number '" + args[0] + "'"); |
1117 } | 900 } |
1118 | 901 |
1119 auto result = request(irccdctl, { | 902 auto json = nlohmann::json::object({ |
1120 { "command", "rule-info" }, | 903 { "command", "rule-info" }, |
1121 { "index", index } | 904 { "index", index } |
1122 }); | 905 }); |
1123 | 906 |
1124 check(result); | 907 request(ctl, std::move(json), [] (auto result) { |
1125 showRule(result, 0); | 908 show_rule(result, 0); |
1126 } | 909 }); |
1127 | 910 } |
1128 /* | 911 |
1129 * RuleRemoveCli. | 912 /* |
1130 * ------------------------------------------------------------------ | 913 * rule_remove_cli. |
1131 */ | 914 * ------------------------------------------------------------------ |
1132 | 915 */ |
1133 RuleRemoveCli::RuleRemoveCli() | 916 |
1134 : Cli("rule-remove", | 917 std::string rule_remove_cli::name() const |
1135 "remove a rule", | 918 { |
1136 "rule-remove index", | 919 return "rule-remove"; |
1137 "Remove an existing rule.\n\n" | 920 } |
1138 "Example:\n" | 921 |
1139 "\tirccdctl rule-remove 0\n" | 922 void rule_remove_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
1140 "\tirccdctl rule-remove 1") | |
1141 { | |
1142 } | |
1143 | |
1144 void RuleRemoveCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
1145 { | 923 { |
1146 if (args.size() < 1) | 924 if (args.size() < 1) |
1147 throw std::invalid_argument("rule-remove requires 1 argument"); | 925 throw std::invalid_argument("rule-remove requires 1 argument"); |
1148 | 926 |
1149 int index = 0; | 927 int index = 0; |
1152 index = std::stoi(args[0]); | 930 index = std::stoi(args[0]); |
1153 } catch (...) { | 931 } catch (...) { |
1154 throw std::invalid_argument("invalid number '" + args[0] + "'"); | 932 throw std::invalid_argument("invalid number '" + args[0] + "'"); |
1155 } | 933 } |
1156 | 934 |
1157 auto result = request(irccdctl, { | 935 request(ctl, { |
1158 { "command", "rule-remove" }, | 936 { "command", "rule-remove" }, |
1159 { "index", index } | 937 { "index", index } |
1160 }); | 938 }); |
1161 | 939 } |
1162 check(result); | 940 |
1163 } | 941 /* |
1164 | 942 * rule_move_cli. |
1165 /* | 943 * ------------------------------------------------------------------ |
1166 * RuleMoveCli. | 944 */ |
1167 * ------------------------------------------------------------------ | 945 |
1168 */ | 946 std::string rule_move_cli::name() const |
1169 | 947 { |
1170 RuleMoveCli::RuleMoveCli() | 948 return "rule-move"; |
1171 : Cli("rule-move", | 949 } |
1172 "move a rule to a new position", | 950 |
1173 "rule-move source destination", | 951 void rule_move_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
1174 "Move a rule from the given source at the specified destination index.\n\n" | |
1175 "The rule will replace the existing one at the given destination moving\ndown every " | |
1176 "other rules. If destination is greater or equal the number of rules,\nthe rule " | |
1177 "is moved to the end.\n\n" | |
1178 "Example:\n" | |
1179 "\tirccdctl rule-move 0 5\n" | |
1180 "\tirccdctl rule-move 4 3") | |
1181 { | |
1182 } | |
1183 | |
1184 void RuleMoveCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args) | |
1185 { | 952 { |
1186 if (args.size() < 2) | 953 if (args.size() < 2) |
1187 throw std::invalid_argument("rule-move requires 2 arguments"); | 954 throw std::invalid_argument("rule-move requires 2 arguments"); |
1188 | 955 |
1189 int from = 0; | 956 int from = 0; |
1194 to = std::stoi(args[1]); | 961 to = std::stoi(args[1]); |
1195 } catch (...) { | 962 } catch (...) { |
1196 throw std::invalid_argument("invalid number"); | 963 throw std::invalid_argument("invalid number"); |
1197 } | 964 } |
1198 | 965 |
1199 check(request(irccdctl, { | 966 request(ctl, { |
1200 { "command", "rule-move" }, | 967 { "command", "rule-move" }, |
1201 { "from", from }, | 968 { "from", from }, |
1202 { "to", to } | 969 { "to", to } |
1203 })); | 970 }); |
1204 } | 971 } |
1205 | 972 |
1206 /* | 973 /* |
1207 * WatchCli. | 974 * WatchCli. |
1208 * ------------------------------------------------------------------ | 975 * ------------------------------------------------------------------ |
1359 std::cout << "username: " << json_util::pretty(v, "username") << "\n"; | 1126 std::cout << "username: " << json_util::pretty(v, "username") << "\n"; |
1360 std::cout << "host: " << json_util::pretty(v, "host") << "\n"; | 1127 std::cout << "host: " << json_util::pretty(v, "host") << "\n"; |
1361 std::cout << "realname: " << json_util::pretty(v, "realname") << "\n"; | 1128 std::cout << "realname: " << json_util::pretty(v, "realname") << "\n"; |
1362 } | 1129 } |
1363 | 1130 |
1364 const std::unordered_map<std::string, std::function<void (const nlohmann::json &)>> events{ | 1131 const std::unordered_map<std::string, std::function<void (const nlohmann::json&)>> events{ |
1365 { "onChannelMode", onChannelMode }, | 1132 { "onChannelMode", onChannelMode }, |
1366 { "onChannelNotice", onChannelNotice }, | 1133 { "onChannelNotice", onChannelNotice }, |
1367 { "onConnect", onConnect }, | 1134 { "onConnect", onConnect }, |
1368 { "onInvite", onInvite }, | 1135 { "onInvite", onInvite }, |
1369 { "onJoin", onJoin }, | 1136 { "onJoin", onJoin }, |
1378 { "onQuery", onQuery }, | 1145 { "onQuery", onQuery }, |
1379 { "onTopic", onTopic }, | 1146 { "onTopic", onTopic }, |
1380 { "onWhois", onWhois } | 1147 { "onWhois", onWhois } |
1381 }; | 1148 }; |
1382 | 1149 |
1150 void get_event(ctl::controller& ctl, std::string fmt) | |
1151 { | |
1152 ctl.recv([&ctl, fmt] (auto code, auto message) { | |
1153 if (code) | |
1154 throw boost::system::system_error(code); | |
1155 | |
1156 auto it = events.find(json_util::to_string(message["event"])); | |
1157 | |
1158 if (it != events.end()) { | |
1159 if (fmt == "json") | |
1160 std::cout << message.dump(4) << std::endl; | |
1161 else { | |
1162 it->second(message); | |
1163 std::cout << std::endl; | |
1164 } | |
1165 } | |
1166 | |
1167 get_event(ctl, std::move(fmt)); | |
1168 }); | |
1169 } | |
1170 | |
1383 } // !namespace | 1171 } // !namespace |
1384 | 1172 |
1385 WatchCli::WatchCli() | 1173 std::string watch_cli::name() const |
1386 : Cli("watch", | 1174 { |
1387 "watch irccd events", | 1175 return "watch"; |
1388 "watch [-f|--format json|native]", | 1176 } |
1389 "Start watching irccd events.\n\n" | 1177 |
1390 "You can use different output formats, native is human readable format, json is\n" | 1178 void watch_cli::exec(ctl::controller& ctl, const std::vector<std::string>& args) |
1391 "pretty formatted json.\n\n" | 1179 { |
1392 "Example:\n" | 1180 auto fmt = format(args); |
1393 "\tirccdctl watch\n" | |
1394 "\tirccdctl watch -f json") | |
1395 { | |
1396 } | |
1397 | |
1398 void WatchCli::exec(Irccdctl& client, const std::vector<std::string>& args) | |
1399 { | |
1400 std::string fmt = format(args); | |
1401 | 1181 |
1402 if (fmt != "native" && fmt != "json") | 1182 if (fmt != "native" && fmt != "json") |
1403 throw std::invalid_argument("invalid format given: " + fmt); | 1183 throw std::invalid_argument("invalid format given: " + fmt); |
1404 | 1184 |
1405 auto id = client.client().onEvent.connect([&] (auto ev) { | 1185 get_event(ctl, fmt); |
1406 try { | |
1407 auto name = ev.find("event"); | |
1408 | |
1409 if (name == ev.end() || !name->is_string()) | |
1410 return; | |
1411 | |
1412 auto it = events.find(*name); | |
1413 | |
1414 // Silently ignore to avoid breaking user output. | |
1415 if (it == events.end()) | |
1416 return; | |
1417 | |
1418 if (fmt == "json") | |
1419 std::cout << ev.dump(4) << std::endl; | |
1420 else { | |
1421 it->second(ev); | |
1422 std::cout << std::endl; | |
1423 } | |
1424 } catch (...) { | |
1425 } | |
1426 }); | |
1427 | |
1428 try { | |
1429 while (client.client().isConnected()) { | |
1430 net_util::poll(500, client); | |
1431 } | |
1432 } catch (const std::exception &ex) { | |
1433 log::warning() << ex.what() << std::endl; | |
1434 } | |
1435 | |
1436 client.client().onEvent.disconnect(id); | |
1437 } | 1186 } |
1438 | 1187 |
1439 } // !cli | 1188 } // !cli |
1440 | 1189 |
1441 } // !irccd | 1190 } // !irccd |