Mercurial > irccd
comparison irccdctl/cli.cpp @ 804:d55a64c6586b
irccdctl: unify CLI output, closes #928 @1h
author | David Demelier <markand@malikania.fr> |
---|---|
date | Wed, 14 Nov 2018 14:07:05 +0100 |
parents | f26bb089232d |
children | 5a421b20a4f4 |
comparison
equal
deleted
inserted
replaced
803:14f9e3b03779 | 804:d55a64c6586b |
---|---|
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 <iomanip> | |
20 #include <ios> | |
19 #include <iostream> | 21 #include <iostream> |
20 | 22 |
21 #include <irccd/json_util.hpp> | 23 #include <irccd/json_util.hpp> |
22 #include <irccd/options.hpp> | 24 #include <irccd/options.hpp> |
23 #include <irccd/string_util.hpp> | 25 #include <irccd/string_util.hpp> |
27 #include <irccd/daemon/rule_service.hpp> | 29 #include <irccd/daemon/rule_service.hpp> |
28 | 30 |
29 #include "cli.hpp" | 31 #include "cli.hpp" |
30 | 32 |
31 using irccd::json_util::deserializer; | 33 using irccd::json_util::deserializer; |
34 using irccd::json_util::pretty; | |
32 | 35 |
33 namespace irccd::ctl { | 36 namespace irccd::ctl { |
34 | 37 |
35 // {{{ helpers | 38 // {{{ helpers |
36 | 39 |
37 namespace { | 40 namespace { |
41 | |
42 template <typename T> | |
43 auto operator<<(std::ostream& out, const std::optional<T>& value) -> std::ostream& | |
44 { | |
45 if (value) | |
46 out << pretty(*value); | |
47 | |
48 return out; | |
49 } | |
38 | 50 |
39 template <typename T> | 51 template <typename T> |
40 auto bind() noexcept -> cli::constructor | 52 auto bind() noexcept -> cli::constructor |
41 { | 53 { |
42 return [] () noexcept { | 54 return [] () noexcept { |
57 return result.find("--format")->second; | 69 return result.find("--format")->second; |
58 | 70 |
59 return "native"; | 71 return "native"; |
60 } | 72 } |
61 | 73 |
62 void onConnect(const nlohmann::json &v) | 74 auto align(std::string_view topic) -> std::ostream& |
63 { | 75 { |
64 std::cout << "event: onConnect\n"; | 76 assert(topic.size() <= 16); |
65 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 77 |
66 } | 78 return std::cout << std::setw(16) << std::left << topic; |
67 | 79 } |
68 void onInvite(const nlohmann::json &v) | 80 |
69 { | 81 void onConnect(const deserializer& v) |
70 std::cout << "event: onInvite\n"; | 82 { |
71 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 83 align("event:") << "onConnect\n"; |
72 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 84 align("server:") << v.get<std::string>("server") << "\n"; |
73 std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; | 85 } |
74 } | 86 |
75 | 87 void onInvite(const deserializer& v) |
76 void onJoin(const nlohmann::json &v) | 88 { |
77 { | 89 align("event:") << "onInvite\n"; |
78 std::cout << "event: onJoin\n"; | 90 align("server:") << v.get<std::string>("server") << "\n"; |
79 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 91 align("origin:") << v.get<std::string>("origin") << "\n"; |
80 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 92 align("channel:") << v.get<std::string>("channel") << "\n"; |
81 std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; | 93 } |
82 } | 94 |
83 | 95 void onJoin(const deserializer& v) |
84 void onKick(const nlohmann::json &v) | 96 { |
85 { | 97 align("event:") << "onJoin\n"; |
86 std::cout << "event: onKick\n"; | 98 align("server:") << v.get<std::string>("server") << "\n"; |
87 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 99 align("origin:") << v.get<std::string>("origin") << "\n"; |
88 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 100 align("channel:") << v.get<std::string>("channel") << "\n"; |
89 std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; | 101 } |
90 std::cout << "target: " << json_util::pretty(v.value("target", "(unknown)")) << "\n"; | 102 |
91 std::cout << "reason: " << json_util::pretty(v.value("reason", "(unknown)")) << "\n"; | 103 void onKick(const deserializer& v) |
92 } | 104 { |
93 | 105 align("event:") << "onKick\n"; |
94 void onMessage(const nlohmann::json &v) | 106 align("server:") << v.get<std::string>("server") << "\n"; |
95 { | 107 align("origin:") << v.get<std::string>("origin") << "\n"; |
96 std::cout << "event: onMessage\n"; | 108 align("channel:") << v.get<std::string>("channel") << "\n"; |
97 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 109 align("target:") << v.get<std::string>("target") << "\n"; |
98 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 110 align("reason:") << v.get<std::string>("reason") << "\n"; |
99 std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; | 111 } |
100 std::cout << "message: " << json_util::pretty(v.value("message", "(unknown)")) << "\n"; | 112 |
101 } | 113 void onMessage(const deserializer& v) |
102 | 114 { |
103 void onMe(const nlohmann::json &v) | 115 align("event:") << "onMessage\n"; |
104 { | 116 align("server:") << v.get<std::string>("server") << "\n"; |
105 std::cout << "event: onMe\n"; | 117 align("origin:") << v.get<std::string>("origin") << "\n"; |
106 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 118 align("channel:") << v.get<std::string>("channel") << "\n"; |
107 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 119 align("message:") << v.get<std::string>("message") << "\n"; |
108 std::cout << "target: " << json_util::pretty(v.value("target", "(unknown)")) << "\n"; | 120 } |
109 std::cout << "message: " << json_util::pretty(v.value("message", "(unknown)")) << "\n"; | 121 |
110 } | 122 void onMe(const deserializer& v) |
111 | 123 { |
112 void onMode(const nlohmann::json &v) | 124 align("event:") << "onMe\n"; |
113 { | 125 align("server:") << v.get<std::string>("server") << "\n"; |
114 std::cout << "event: onMode\n"; | 126 align("origin:") << v.get<std::string>("origin") << "\n"; |
115 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 127 align("target:") << v.get<std::string>("target") << "\n"; |
116 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 128 align("message:") << v.get<std::string>("message") << "\n"; |
117 std::cout << "mode: " << json_util::pretty(v.value("mode", "(unknown)")) << "\n"; | 129 } |
118 } | 130 |
119 | 131 void onMode(const deserializer& v) |
120 void onNames(const nlohmann::json &v) | 132 { |
121 { | 133 align("event:") << "onMode\n"; |
122 std::cout << "event: onNames\n"; | 134 align("server:") << v.get<std::string>("server") << "\n"; |
123 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 135 align("origin:") << v.get<std::string>("origin") << "\n"; |
124 std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; | 136 align("mode:") << v.get<std::string>("mode") << "\n"; |
125 std::cout << "names: " << json_util::pretty(v.value("names", "(unknown)")) << "\n"; | 137 } |
126 } | 138 |
127 | 139 void onNames(const deserializer& v) |
128 void onNick(const nlohmann::json &v) | 140 { |
129 { | 141 align("event:") << "onNames\n"; |
130 std::cout << "event: onNick\n"; | 142 align("server:") << v.get<std::string>("server") << "\n"; |
131 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 143 align("channel:") << v.get<std::string>("channel") << "\n"; |
132 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 144 align("names:") << v.get<std::string>("names") << "\n"; |
133 std::cout << "nickname: " << json_util::pretty(v.value("nickname", "(unknown)")) << "\n"; | 145 } |
134 } | 146 |
135 | 147 void onNick(const deserializer& v) |
136 void onNotice(const nlohmann::json &v) | 148 { |
137 { | 149 align("event:") << "onNick\n"; |
138 std::cout << "event: onNotice\n"; | 150 align("server:") << v.get<std::string>("server") << "\n"; |
139 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 151 align("origin:") << v.get<std::string>("origin") << "\n"; |
140 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 152 align("nickname:") << v.get<std::string>("nickname") << "\n"; |
141 std::cout << "message: " << json_util::pretty(v.value("message", "(unknown)")) << "\n"; | 153 } |
142 } | 154 |
143 | 155 void onNotice(const deserializer& v) |
144 void onPart(const nlohmann::json &v) | 156 { |
145 { | 157 align("event:") << "onNotice\n"; |
146 std::cout << "event: onPart\n"; | 158 align("server:") << v.get<std::string>("server") << "\n"; |
147 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 159 align("origin:") << v.get<std::string>("origin") << "\n"; |
148 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 160 align("message:") << v.get<std::string>("message") << "\n"; |
149 std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; | 161 } |
150 std::cout << "reason: " << json_util::pretty(v.value("reason", "(unknown)")) << "\n"; | 162 |
151 } | 163 void onPart(const deserializer& v) |
152 | 164 { |
153 void onTopic(const nlohmann::json &v) | 165 align("event:") << "onPart\n"; |
154 { | 166 align("server:") << v.get<std::string>("server") << "\n"; |
155 std::cout << "event: onTopic\n"; | 167 align("origin:") << v.get<std::string>("origin") << "\n"; |
156 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 168 align("channel:") << v.get<std::string>("channel") << "\n"; |
157 std::cout << "origin: " << json_util::pretty(v.value("origin", "(unknown)")) << "\n"; | 169 align("reason:") << v.get<std::string>("reason") << "\n"; |
158 std::cout << "channel: " << json_util::pretty(v.value("channel", "(unknown)")) << "\n"; | 170 } |
159 std::cout << "topic: " << json_util::pretty(v.value("topic", "(unknown)")) << "\n"; | 171 |
160 } | 172 void onTopic(const deserializer& v) |
161 | 173 { |
162 void onWhois(const nlohmann::json &v) | 174 align("event:") << "onTopic\n"; |
163 { | 175 align("server:") << v.get<std::string>("server") << "\n"; |
164 std::cout << "event: onWhois\n"; | 176 align("origin:") << v.get<std::string>("origin") << "\n"; |
165 std::cout << "server: " << json_util::pretty(v.value("server", "(unknown)")) << "\n"; | 177 align("channel:") << v.get<std::string>("channel") << "\n"; |
166 std::cout << "nickname: " << json_util::pretty(v.value("nickname", "(unknown)")) << "\n"; | 178 align("topic:") << v.get<std::string>("topic") << "\n"; |
167 std::cout << "username: " << json_util::pretty(v.value("username", "(unknown)")) << "\n"; | 179 } |
168 std::cout << "hostname: " << json_util::pretty(v.value("hostname", "(unknown)")) << "\n"; | 180 |
169 std::cout << "realname: " << json_util::pretty(v.value("realname", "(unknown)")) << "\n"; | 181 void onWhois(const deserializer& v) |
182 { | |
183 align("event:") << "onWhois\n"; | |
184 align("server:") << v.get<std::string>("server") << "\n"; | |
185 align("nickname:") << v.get<std::string>("nickname") << "\n"; | |
186 align("username:") << v.get<std::string>("username") << "\n"; | |
187 align("hostname:") << v.get<std::string>("hostname") << "\n"; | |
188 align("realname:") << v.get<std::string>("realname") << "\n"; | |
170 } | 189 } |
171 | 190 |
172 const std::unordered_map<std::string_view, std::function<void (const nlohmann::json&)>> events{ | 191 const std::unordered_map<std::string_view, std::function<void (const nlohmann::json&)>> events{ |
173 { "onConnect", onConnect }, | 192 { "onConnect", onConnect }, |
174 { "onInvite", onInvite }, | 193 { "onInvite", onInvite }, |
186 }; | 205 }; |
187 | 206 |
188 void get_event(ctl::controller& ctl, std::string fmt) | 207 void get_event(ctl::controller& ctl, std::string fmt) |
189 { | 208 { |
190 ctl.recv([&ctl, fmt] (auto code, auto message) { | 209 ctl.recv([&ctl, fmt] (auto code, auto message) { |
210 const deserializer doc(message); | |
211 | |
191 if (code) | 212 if (code) |
192 throw std::system_error(code); | 213 throw std::system_error(code); |
193 | 214 |
194 const auto event = deserializer(message).get<std::string>("event"); | 215 const auto event = doc.get<std::string>("event"); |
195 const auto it = events.find(event ? *event : ""); | 216 const auto it = events.find(event ? *event : ""); |
196 | 217 |
197 if (it != events.end()) { | 218 if (it != events.end()) { |
198 if (fmt == "json") | 219 if (fmt == "json") |
199 std::cout << message.dump(4) << std::endl; | 220 std::cout << message.dump(4) << std::endl; |
200 else { | 221 else { |
201 it->second(message); | 222 it->second(doc); |
202 std::cout << std::endl; | 223 std::cout << std::endl; |
203 } | 224 } |
204 } | 225 } |
205 | 226 |
206 get_event(ctl, std::move(fmt)); | 227 get_event(ctl, std::move(fmt)); |
313 { "variable", args[1] } | 334 { "variable", args[1] } |
314 }); | 335 }); |
315 | 336 |
316 request(ctl, std::move(json), [args] (auto result) { | 337 request(ctl, std::move(json), [args] (auto result) { |
317 if (result["variables"].is_object()) | 338 if (result["variables"].is_object()) |
318 std::cout << json_util::pretty(result["variables"][args[1]]) << std::endl; | 339 std::cout << pretty(result["variables"][args[1]]) << std::endl; |
319 }); | 340 }); |
320 } | 341 } |
321 | 342 |
322 void plugin_config_cli::getall(ctl::controller& ctl, const std::vector<std::string> &args) | 343 void plugin_config_cli::getall(ctl::controller& ctl, const std::vector<std::string> &args) |
323 { | 344 { |
328 | 349 |
329 request(ctl, json, [] (auto result) { | 350 request(ctl, json, [] (auto result) { |
330 const auto variables = result["variables"]; | 351 const auto variables = result["variables"]; |
331 | 352 |
332 for (auto v = variables.begin(); v != variables.end(); ++v) | 353 for (auto v = variables.begin(); v != variables.end(); ++v) |
333 std::cout << std::setw(16) << std::left << v.key() << " : " << json_util::pretty(v.value()) << std::endl; | 354 std::cout << std::setw(16) << std::left << v.key() << " : " << pretty(v.value()) << std::endl; |
334 }); | 355 }); |
335 } | 356 } |
336 | 357 |
337 auto plugin_config_cli::get_name() const noexcept -> std::string_view | 358 auto plugin_config_cli::get_name() const noexcept -> std::string_view |
338 { | 359 { |
376 }); | 397 }); |
377 | 398 |
378 request(ctl, json, [] (auto result) { | 399 request(ctl, json, [] (auto result) { |
379 const deserializer doc(result); | 400 const deserializer doc(result); |
380 | 401 |
381 std::cout << std::boolalpha; | 402 align("author:") << doc.get<std::string>("author") << std::endl; |
382 std::cout << "Author : " | 403 align("license:") << doc.get<std::string>("license") << std::endl; |
383 << doc.get<std::string>("author").value_or("(unknown)") << std::endl; | 404 align("summary:") << doc.get<std::string>("summary") << std::endl; |
384 std::cout << "License : " | 405 align("version:") << doc.get<std::string>("version") << std::endl; |
385 << doc.get<std::string>("license").value_or("(unknown)") << std::endl; | |
386 std::cout << "Summary : " | |
387 << doc.get<std::string>("summary").value_or("(unknown)") << std::endl; | |
388 std::cout << "Version : " | |
389 << doc.get<std::string>("version").value_or("(unknown)") << std::endl; | |
390 }); | 406 }); |
391 } | 407 } |
392 | 408 |
393 // }}} | 409 // }}} |
394 | 410 |
642 return "accept"; | 658 return "accept"; |
643 else | 659 else |
644 return "drop"; | 660 return "drop"; |
645 }; | 661 }; |
646 | 662 |
647 std::cout << "rule: " << index << std::endl; | 663 align("rule:") << index << std::endl; |
648 std::cout << "servers: " << unjoin(json["servers"]) << std::endl; | 664 align("servers:") << unjoin(json["servers"]) << std::endl; |
649 std::cout << "channels: " << unjoin(json["channels"]) << std::endl; | 665 align("channels:") << unjoin(json["channels"]) << std::endl; |
650 std::cout << "plugins: " << unjoin(json["plugins"]) << std::endl; | 666 align("plugins:") << unjoin(json["plugins"]) << std::endl; |
651 std::cout << "events: " << unjoin(json["events"]) << std::endl; | 667 align("events:") << unjoin(json["events"]) << std::endl; |
652 std::cout << "action: " << unstr(json["action"]) << std::endl; | 668 align("action:") << unstr(json["action"]) << std::endl; |
653 std::cout << std::endl; | |
654 } | 669 } |
655 | 670 |
656 auto rule_info_cli::get_name() const noexcept -> std::string_view | 671 auto rule_info_cli::get_name() const noexcept -> std::string_view |
657 { | 672 { |
658 return "rule-info"; | 673 return "rule-info"; |
689 | 704 |
690 void rule_list_cli::exec(ctl::controller& ctl, const std::vector<std::string>&) | 705 void rule_list_cli::exec(ctl::controller& ctl, const std::vector<std::string>&) |
691 { | 706 { |
692 request(ctl, {{ "command", "rule-list" }}, [] (auto result) { | 707 request(ctl, {{ "command", "rule-list" }}, [] (auto result) { |
693 auto pos = 0; | 708 auto pos = 0; |
694 | 709 auto length = result["list"].size(); |
695 for (const auto& obj : result["list"]) | 710 |
696 if (obj.is_object()) | 711 for (const auto& obj : result["list"]) { |
697 rule_info_cli::print(obj, pos++); | 712 if (!obj.is_object()) |
713 continue; | |
714 | |
715 rule_info_cli::print(obj, pos++); | |
716 | |
717 if (pos < length) | |
718 std::cout << std::endl; | |
719 } | |
698 }); | 720 }); |
699 } | 721 } |
700 | 722 |
701 // }}} | 723 // }}} |
702 | 724 |
845 { "command", "server-info" }, | 867 { "command", "server-info" }, |
846 { "server", args[0] } | 868 { "server", args[0] } |
847 }); | 869 }); |
848 | 870 |
849 request(ctl, std::move(json), [] (auto result) { | 871 request(ctl, std::move(json), [] (auto result) { |
850 std::cout << std::boolalpha; | 872 const deserializer doc(result); |
851 std::cout << "Name : " << json_util::pretty(result["name"]) << std::endl; | 873 |
852 std::cout << "Hostname : " << json_util::pretty(result["hostname"]) << std::endl; | 874 align("name:") << doc.get<std::string>("name") << std::endl; |
853 std::cout << "Port : " << json_util::pretty(result["port"]) << std::endl; | 875 align("hostname:") << doc.get<std::string>("hostname") << std::endl; |
854 std::cout << "Ipv6 : " << json_util::pretty(result["ipv6"]) << std::endl; | 876 align("port:") << doc.get<std::uint64_t>("port") << std::endl; |
855 std::cout << "SSL : " << json_util::pretty(result["ssl"]) << std::endl; | 877 align("nickname:") << doc.get<std::string>("nickname") << std::endl; |
856 std::cout << "SSL verified : " << json_util::pretty(result["sslVerify"]) << std::endl; | 878 align("username:") << doc.get<std::string>("username") << std::endl; |
857 std::cout << "Channels : "; | 879 align("realname:") << doc.get<std::string>("realname") << std::endl; |
880 align("ipv4:") << doc.get<bool>("ipv4") << std::endl; | |
881 align("ipv6:") << doc.get<bool>("ipv6") << std::endl; | |
882 align("ssl:") << doc.get<bool>("ssl") << std::endl; | |
883 align("channels:"); | |
858 | 884 |
859 for (const auto& v : result["channels"]) | 885 for (const auto& v : result["channels"]) |
860 if (v.is_string()) | 886 if (v.is_string()) |
861 std::cout << v.template get<std::string>() << " "; | 887 std::cout << v.template get<std::string>() << " "; |
862 | 888 |
863 std::cout << std::endl; | 889 std::cout << std::endl; |
864 | |
865 std::cout << "Nickname : " << json_util::pretty(result["nickname"]) << std::endl; | |
866 std::cout << "User name : " << json_util::pretty(result["username"]) << std::endl; | |
867 std::cout << "Real name : " << json_util::pretty(result["realname"]) << std::endl; | |
868 }); | 890 }); |
869 } | 891 } |
870 | 892 |
871 // }}} | 893 // }}} |
872 | 894 |