comparison irccdctl/cli.cpp @ 345:006452e4a997

Irccdctl: unify cli commands
author David Demelier <markand@malikania.fr>
date Sun, 13 Nov 2016 09:45:54 +0100
parents 4665fffff6f2
children 24b1709093e7
comparison
equal deleted inserted replaced
344:4665fffff6f2 345:006452e4a997
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 <iostream>
20
19 #include <json.hpp> 21 #include <json.hpp>
20 22
21 #include "cli.hpp" 23 #include "cli.hpp"
24 #include "elapsed-timer.hpp"
22 #include "irccdctl.hpp" 25 #include "irccdctl.hpp"
26 #include "options.hpp"
23 #include "util.hpp" 27 #include "util.hpp"
24 #include "elapsed-timer.hpp"
25 28
26 namespace irccd { 29 namespace irccd {
30
31 /*
32 * Cli.
33 * ------------------------------------------------------------------
34 */
27 35
28 void Cli::check(const nlohmann::json &response) 36 void Cli::check(const nlohmann::json &response)
29 { 37 {
30 if (!util::json::getBool(response, "status", false)) { 38 if (!util::json::getBool(response, "status", false)) {
31 auto error = util::json::getString(response, "error"); 39 auto error = util::json::getString(response, "error");
78 void Cli::call(Irccdctl &irccdctl, nlohmann::json args) 86 void Cli::call(Irccdctl &irccdctl, nlohmann::json args)
79 { 87 {
80 check(request(irccdctl, args)); 88 check(request(irccdctl, args));
81 } 89 }
82 90
91 namespace cli {
92
93 /*
94 * PluginConfigCli.
95 * ------------------------------------------------------------------
96 */
97
98 void PluginConfigCli::set(Irccdctl &irccdctl, const std::vector<std::string> &args)
99 {
100 check(request(irccdctl, nlohmann::json::object({
101 { "plugin", args[0] },
102 { "variable", args[1] },
103 { "value", args[2] }
104 })));
105 }
106
107 void PluginConfigCli::get(Irccdctl &irccdctl, const std::vector<std::string> &args)
108 {
109 auto result = request(irccdctl, nlohmann::json::object({
110 { "plugin", args[0] },
111 { "variable", args[1] }
112 }));
113
114 check(result);
115
116 if (result["variables"].is_object())
117 std::cout << util::json::pretty(result["variables"][args[1]]) << std::endl;
118 }
119
120 void PluginConfigCli::getall(Irccdctl &irccdctl, const std::vector<std::string> &args)
121 {
122 auto result = request(irccdctl, nlohmann::json::object({{ "plugin", args[0] }}));
123
124 check(result);
125
126 auto variables = result["variables"];
127
128 for (auto v = variables.begin(); v != variables.end(); ++v)
129 std::cout << std::setw(16) << std::left << v.key() << " : " << util::json::pretty(v.value()) << std::endl;
130 }
131
132 PluginConfigCli::PluginConfigCli()
133 : Cli("plugin-config",
134 "configure a plugin",
135 "plugin-config plugin [variable] [value]",
136 "Get or set plugin configuration.\n\n"
137 "Examples:\n"
138 "\tirccdctl plugin-config ask")
139 {
140 }
141
142 void PluginConfigCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
143 {
144 switch (args.size()) {
145 case 3:
146 set(irccdctl, args);
147 break;
148 case 2:
149 get(irccdctl, args);
150 break;
151 case 1:
152 getall(irccdctl, args);
153 break;
154 default:
155 throw std::invalid_argument("plugin-config requires at least 1 argument");
156 }
157 }
158
159 /*
160 * PluginInfoCli.
161 * ------------------------------------------------------------------
162 */
163
164 PluginInfoCli::PluginInfoCli()
165 : Cli("plugin-info",
166 "get plugin information",
167 "plugin-info plugin",
168 "Get plugin information\n\n"
169 "Example:\n"
170 "\tirccdctl plugin-info ask"
171 )
172 {
173 }
174
175 void PluginInfoCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
176 {
177 if (args.size() < 1)
178 throw std::invalid_argument("plugin-info requires 1 argument");
179
180 auto result = request(irccdctl, {{ "plugin", args[0] }});
181
182 std::cout << std::boolalpha;
183 std::cout << "Author : " << util::json::getString(result, "author") << std::endl;
184 std::cout << "License : " << util::json::getString(result, "license") << std::endl;
185 std::cout << "Summary : " << util::json::getString(result, "summary") << std::endl;
186 std::cout << "Version : " << util::json::getString(result, "version") << std::endl;
187 }
188
189 /*
190 * PluginListCli.
191 * ------------------------------------------------------------------
192 */
193
194 PluginListCli::PluginListCli()
195 : Cli("plugin-list",
196 "list loaded plugins",
197 "plugin-list",
198 "Get the list of all loaded plugins.\n\n"
199 "Example:\n"
200 "\tirccdctl plugin-list")
201 {
202 }
203
204 void PluginListCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &)
205 {
206 auto result = request(irccdctl);
207
208 for (const auto &value : result["list"])
209 if (value.is_string())
210 std::cout << value.get<std::string>() << std::endl;
211 }
212
213 /*
214 * PluginLoadCli.
215 * ------------------------------------------------------------------
216 */
217
218 PluginLoadCli::PluginLoadCli()
219 : Cli("plugin-load",
220 "load a plugin",
221 "plugin-load logger",
222 "Load a plugin into the irccd instance.\n\n"
223 "Example:\n"
224 "\tirccdctl plugin-load logger")
225 {
226 }
227
228 void PluginLoadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
229 {
230 if (args.size() < 1)
231 throw std::invalid_argument("plugin-load requires 1 argument");
232
233 check(request(irccdctl, {{"plugin", args[0]}}));
234 }
235
236 /*
237 * PluginReloadCli.
238 * ------------------------------------------------------------------
239 */
240
241 PluginReloadCli::PluginReloadCli()
242 : Cli("plugin-reload",
243 "reload a plugin",
244 "plugin-reload plugin",
245 "Call the onReload event on the specified plugin.")
246 {
247 }
248
249 void PluginReloadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
250 {
251 if (args.size() < 1)
252 throw std::invalid_argument("plugin-reload requires 1 argument");
253
254 check(request(irccdctl, {{ "plugin", args[0] }}));
255 }
256
257 /*
258 * PluginUnloadCli.
259 * ------------------------------------------------------------------
260 */
261
262 PluginUnloadCli::PluginUnloadCli()
263 : Cli("plugin-unload",
264 "unload a plugin",
265 "plugin-unload plugin",
266 "Unload a loaded plugin from the irccd instance.\n\n"
267 "Example:\n"
268 "tirccdctl plugin-unload logger")
269 {
270 }
271
272 void PluginUnloadCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
273 {
274 if (args.size() < 1)
275 throw std::invalid_argument("plugin-unload requires 1 argument");
276
277 check(request(irccdctl, {{ "plugin", args[0] }}));
278 }
279
280 /*
281 * ServerChannelCli.
282 * ------------------------------------------------------------------
283 */
284
285 ServerChannelMode::ServerChannelMode()
286 : Cli("server-cmode",
287 "change channel mode",
288 "server-cmode server channel mode",
289 "Change the mode of the specified channel.\n\n"
290 "Example:\n"
291 "\tirccdctl server-cmode freenode #staff +t")
292 {
293 }
294
295 void ServerChannelMode::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
296 {
297 if (args.size() < 3)
298 throw std::invalid_argument("server-cmode requires 3 arguments");
299
300 check(request(irccdctl, {
301 { "command", "server-cmode" },
302 { "server", args[0] },
303 { "channel", args[1] },
304 { "mode", args[2] }
305 }));
306 }
307
308 /*
309 * ServerChannelNoticeCli.
310 * ------------------------------------------------------------------
311 */
312
313 ServerChannelNoticeCli::ServerChannelNoticeCli()
314 : Cli("server-cnotice",
315 "send a channel notice",
316 "server-cnotice server channel message",
317 "Send a message notice on a channel.\n\n"
318 "Example:\n"
319 "\tirccdctl server-cnotice freenode #staff \"Don't flood!\"")
320 {
321 }
322
323 void ServerChannelNoticeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
324 {
325 if (args.size() < 3)
326 throw std::invalid_argument("server-cnotice requires 3 arguments");
327
328 check(request(irccdctl, {
329 { "command", "server-cnotice" },
330 { "server", args[0] },
331 { "channel", args[1] },
332 { "message", args[2] }
333 }));
334 }
335
336 /*
337 * ServerConnectCli.
338 * ------------------------------------------------------------------
339 */
340
341 namespace {
342
343 option::Result parse(std::vector<std::string> &args)
344 {
345 option::Options options{
346 { "-c", true },
347 { "--command", true },
348 { "-n", true },
349 { "--nickname", true },
350 { "-r", true },
351 { "--realname", true },
352 { "-S", false },
353 { "--ssl-verify", false },
354 { "-s", false },
355 { "--ssl", false },
356 { "-u", true },
357 { "--username", true }
358 };
359
360 return option::read(args, options);
361 }
362
363 } // !namespace
364
365 ServerConnectCli::ServerConnectCli()
366 : Cli("server-connect",
367 "add a server",
368 "server-connect [options] id host [port]",
369 "Connect to a server.\n\n"
370 "Available options:\n"
371 " -c, --command\t\tspecify the command char\n"
372 " -n, --nickname\tspecify a nickname\n"
373 " -r, --realname\tspecify a real name\n"
374 " -S, --ssl-verify\tverify SSL\n"
375 " -s, --ssl\t\tconnect using SSL\n"
376 " -u, --username\tspecify a user name\n\n"
377 "Example:\n"
378 "\tirccdctl server-connect -n jean example irc.example.org\n"
379 "\tirccdctl server-connect --ssl example irc.example.org 6697")
380 {
381 }
382
383 void ServerConnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
384 {
385 std::vector<std::string> copy(args);
386
387 option::Result result = parse(copy);
388 option::Result::const_iterator it;
389
390 if (copy.size() < 2)
391 throw std::invalid_argument("server-connect requires at least 2 arguments");
392
393 auto object = nlohmann::json::object({
394 { "name", copy[0] },
395 { "host", copy[1] }
396 });
397
398 if (copy.size() == 3) {
399 if (!util::isNumber(copy[2]))
400 throw std::invalid_argument("invalid port number");
401
402 object["port"] = std::stoi(copy[2]);
403 }
404
405 if (result.count("-S") > 0 || result.count("--ssl-verify") > 0)
406 object["sslVerify"] = true;
407 if (result.count("-s") > 0 || result.count("--ssl") > 0)
408 object["ssl"] = true;
409 if ((it = result.find("-n")) != result.end() || (it = result.find("--nickname")) != result.end())
410 object["nickname"] = it->second;
411 if ((it = result.find("-r")) != result.end() || (it = result.find("--realname")) != result.end())
412 object["realname"] = it->second;
413 if ((it = result.find("-u")) != result.end() || (it = result.find("--username")) != result.end())
414 object["username"] = it->second;
415
416 check(request(irccdctl, object));
417 }
418
419 /*
420 * ServerDisconnectCli.
421 * ------------------------------------------------------------------
422 */
423
424 ServerDisconnectCli::ServerDisconnectCli()
425 : Cli("server-disconnect",
426 "disconnect server",
427 "server-disconnect [server]",
428 "Disconnect from a server.\n\n"
429 "If server is not specified, irccd disconnects all servers.\n\n"
430 "Example:\n"
431 "\tirccdctl server-disconnect localhost")
432 {
433 }
434
435 void ServerDisconnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
436 {
437 auto object = nlohmann::json::object({
438 { "command", "server-disconnect" }
439 });
440
441 if (args.size() > 0)
442 object["server"] = args[0];
443
444 check(request(irccdctl, object));
445 }
446
447 /*
448 * ServerInfoCli.
449 * ------------------------------------------------------------------
450 */
451
452 ServerInfoCli::ServerInfoCli()
453 : Cli("server-info",
454 "get server information",
455 "server-info server",
456 "Get information about a server.\n\n"
457 "Example:\n"
458 "\tirccdctl server-info freenode")
459 {
460 }
461
462 void ServerInfoCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
463 {
464 if (args.size() < 1)
465 throw std::invalid_argument("server-info requires 1 argument");
466
467 auto result = request(irccdctl, {
468 { "command", "server-info" },
469 { "server", args[0] }
470 });
471
472 check(result);
473
474 std::cout << std::boolalpha;
475 std::cout << "Name : " << util::json::pretty(result["name"]) << std::endl;
476 std::cout << "Host : " << util::json::pretty(result["host"]) << std::endl;
477 std::cout << "Port : " << util::json::pretty(result["port"]) << std::endl;
478 std::cout << "Ipv6 : " << util::json::pretty(result["ipv6"]) << std::endl;
479 std::cout << "SSL : " << util::json::pretty(result["ssl"]) << std::endl;
480 std::cout << "SSL verified : " << util::json::pretty(result["sslVerify"]) << std::endl;
481 std::cout << "Channels : ";
482
483 for (const auto &v : result["channels"])
484 if (v.is_string())
485 std::cout << v.get<std::string>() << " ";
486
487 std::cout << std::endl;
488
489 std::cout << "Nickname : " << util::json::pretty(result["nickname"]) << std::endl;
490 std::cout << "User name : " << util::json::pretty(result["username"]) << std::endl;
491 std::cout << "Real name : " << util::json::pretty(result["realname"]) << std::endl;
492 }
493
494 /*
495 * ServerInviteCli.
496 * ------------------------------------------------------------------
497 */
498
499 ServerInviteCli::ServerInviteCli()
500 : Cli("server-invite",
501 "invite someone",
502 "server-invite server nickname channel",
503 "Invite the specified target on the channel.\n\n"
504 "Example:\n"
505 "\tirccdctl server-invite freenode xorg62 #staff")
506 {
507 }
508
509 void ServerInviteCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
510 {
511 if (args.size() < 3)
512 throw std::invalid_argument("server-invite requires 3 arguments");
513
514 check(request(irccdctl, {
515 { "command", "server-invite" },
516 { "server", args[0] },
517 { "target", args[1] },
518 { "channel", args[2] }
519 }));
520 }
521
522 /*
523 * ServerJoinCli.
524 * ------------------------------------------------------------------
525 */
526
527 ServerJoinCli::ServerJoinCli()
528 : Cli("server-join",
529 "join a channel",
530 "server-join server channel [password]",
531 "Join the specified channel, the password is optional.\n\n"
532 "Example:\n"
533 "\tirccdctl server-join freenode #test\n"
534 "\tirccdctl server-join freenode #private-club secret")
535 {
536 }
537
538 void ServerJoinCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
539 {
540 if (args.size() < 2)
541 throw std::invalid_argument("server-join requires at least 2 arguments");
542
543 auto object = nlohmann::json::object({
544 { "server", args[0] },
545 { "channel", args[1] }
546 });
547
548 if (args.size() == 3)
549 object["password"] = args[2];
550
551 check(request(irccdctl, object));
552 }
553
554 /*
555 * ServerKickCli.
556 * ------------------------------------------------------------------
557 */
558
559 ServerKickCli::ServerKickCli()
560 : Cli("server-kick",
561 "kick someone from a channel",
562 "server-kick server target channel [reason]",
563 "Kick the specified target from the channel, the reason is optional.\n\n"
564 "Example:\n"
565 "\tirccdctl server-kick freenode jean #staff \"Stop flooding\"")
566 {
567 }
568
569 void ServerKickCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
570 {
571 if (args.size() < 3)
572 throw std::invalid_argument("server-kick requires at least 3 arguments ");
573
574 auto object = nlohmann::json::object({
575 { "server", args[0] },
576 { "target", args[1] },
577 { "channel", args[2] }
578 });
579
580 if (args.size() == 4)
581 object["reason"] = args[3];
582
583 check(request(irccdctl, object));
584 }
585
586 /*
587 * ServerListCli.
588 * ------------------------------------------------------------------
589 */
590
591 ServerListCli::ServerListCli()
592 : Cli("server-list",
593 "get list of servers",
594 "server-list\n\n",
595 "Get the list of all connected servers.\n\n"
596 "Example:\n"
597 "\tirccdctl server-list")
598 {
599 }
600
601 void ServerListCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &)
602 {
603 auto response = request(irccdctl);
604
605 check(response);
606
607 for (const auto &n : response["list"])
608 if (n.is_string())
609 std::cout << n.get<std::string>() << std::endl;
610 }
611
612 /*
613 * ServerMeCli.
614 * ------------------------------------------------------------------
615 */
616
617 ServerMeCli::ServerMeCli()
618 : Cli("server-me",
619 "send an action emote",
620 "server-me server target message",
621 "Send an action emote.\n\n"
622 "Example:\n"
623 "\tirccdctl server-me freenode #staff \"going back soon\"")
624 {
625 }
626
627 void ServerMeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
628 {
629 if (args.size() < 3)
630 throw std::runtime_error("server-me requires 3 arguments");
631
632 check(request(irccdctl, {
633 { "server", args[0] },
634 { "target", args[1] },
635 { "message", args[2] }
636 }));
637 }
638
639 /*
640 * ServerMessageCli.
641 * ------------------------------------------------------------------
642 */
643
644 ServerMessageCli::ServerMessageCli()
645 : Cli("server-message",
646 "send a message",
647 "server-message server target message",
648 "Send a message to the specified target or channel.\n\n"
649 "Example:\n"
650 "\tirccdctl server-message freenode #staff \"Hello from irccd\"")
651 {
652 }
653
654 void ServerMessageCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
655 {
656 if (args.size() < 3)
657 throw std::invalid_argument("server-message requires 3 arguments");
658
659 check(request(irccdctl, {
660 { "server", args[0] },
661 { "target", args[1] },
662 { "message", args[2] }
663 }));
664 }
665
666 /*
667 * ServerModeCli.
668 * ------------------------------------------------------------------
669 */
670
671 ServerModeCli::ServerModeCli()
672 : Cli("server-mode",
673 "the the user mode",
674 "server-mode server mode",
675 "Set the irccd's user mode.\n\n"
676 "Example:\n"
677 "\tirccdctl server-mode +i")
678 {
679 }
680
681 void ServerModeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
682 {
683 if (args.size() < 2)
684 throw std::invalid_argument("server-mode requires 2 arguments");
685
686 check(request(irccdctl, {
687 { "server", args[0] },
688 { "mode", args[1] }
689 }));
690 }
691
692 /*
693 * ServerNickCli.
694 * ------------------------------------------------------------------
695 */
696
697 ServerNickCli::ServerNickCli()
698 : Cli("server-nick",
699 "change your nickname",
700 "server-nick server nickname",
701 "Change irccd's nickname.\n\n"
702 "Example:\n"
703 "\tirccdctl server-nick freenode david")
704 {
705 }
706
707 void ServerNickCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
708 {
709 if (args.size() < 2)
710 throw std::invalid_argument("server-nick requires 2 arguments");
711
712 check(request(irccdctl, {
713 { "server", args[0] },
714 { "nickname", args[1] }
715 }));
716 }
717
718 /*
719 * ServerNoticeCli.
720 * ------------------------------------------------------------------
721 */
722
723 ServerNoticeCli::ServerNoticeCli()
724 : Cli("server-notice",
725 "send a private notice",
726 "server-notice server target message",
727 "Send a private notice to the specified target.\n\n"
728 "Example:\n"
729 "\tirccdctl server-notice freenode jean \"I know you are here.\"")
730 {
731 }
732
733 void ServerNoticeCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
734 {
735 if (args.size() < 3)
736 throw std::invalid_argument("server-notice requires 3 arguments");
737
738 check(request(irccdctl, {
739 { "server", args[0] },
740 { "target", args[1] },
741 { "message", args[2] }
742 }));
743 }
744
745 /*
746 * ServerPartCli.
747 * ------------------------------------------------------------------
748 */
749
750 ServerPartCli::ServerPartCli()
751 : Cli("server-part",
752 "leave a channel",
753 "server-part server channel [reason]",
754 "Leave the specified channel, the reason is optional.\n\n"
755 "Not all IRC servers support giving a reason to leave a channel, do not "
756 "specify it if this is a concern.\n\n"
757 "Example:\n"
758 "\tirccdctl server-part freenode #staff"
759 "\tirccdctl server-part freenode #botwar \"too noisy\"")
760 {
761 }
762
763 void ServerPartCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
764 {
765 if (args.size() < 2)
766 throw std::invalid_argument("server-part requires at least 2 arguments");
767
768 auto object = nlohmann::json::object({
769 { "server", args[0] },
770 { "channel", args[1] }
771 });
772
773 if (args.size() >= 3)
774 object["reason"] = args[2];
775
776 check(request(irccdctl, object));
777 }
778
779 /*
780 * ServerReconnectCli.
781 * ------------------------------------------------------------------
782 */
783
784 ServerReconnectCli::ServerReconnectCli()
785 : Cli("server-reconnect",
786 "force reconnection of a server",
787 "server-reconnect [server]",
788 "Force reconnection of one or all servers.\n\n"
789 "If server is not specified, all servers will try to reconnect.\n\n"
790 "Example:\n"
791 "\tirccdctl server-reconnect\n"
792 "\tirccdctl server-reconnect wanadoo")
793 {
794 }
795
796 void ServerReconnectCli::exec(Irccdctl &irccdctl, const std::vector<std::string> &args)
797 {
798 auto object = nlohmann::json::object({
799 { "command", "server-reconnect" }
800 });
801
802 if (args.size() >= 1)
803 object["server"] = args[0];
804
805 check(request(irccdctl, object));
806 }
807
808 } // !cli
809
83 } // !irccd 810 } // !irccd