Line data Source code
1 : /**
2 : * Copyright Soramitsu Co., Ltd. All Rights Reserved.
3 : * SPDX-License-Identifier: Apache-2.0
4 : */
5 :
6 : #ifndef IROHA_CLI_INTERACTIVE_COMMON_CLI_HPP
7 : #define IROHA_CLI_INTERACTIVE_COMMON_CLI_HPP
8 :
9 : #include <algorithm>
10 : #include <ciso646>
11 : #include <iostream>
12 : #include <memory>
13 : #include <string>
14 : #include <unordered_map>
15 : #include <vector>
16 :
17 : #include <boost/optional.hpp>
18 :
19 : namespace parser {
20 : boost::optional<std::string> parseFirstCommand(std::string line);
21 : }
22 :
23 : namespace iroha_cli {
24 : namespace interactive {
25 :
26 : /**
27 : * Parsing menu context, used to identify the context of parsing
28 : */
29 : enum MenuContext {
30 : /**
31 : * Main menu context, used to print all commands/queries
32 : */
33 : MAIN,
34 : /**
35 : * Result menu, used for send, save tx/query
36 : */
37 : RESULT
38 : };
39 :
40 : /**
41 : * Data structure for parameter data
42 : */
43 : struct ParamData {
44 : /**
45 : * Message to display when prompting for user input
46 : */
47 : std::string message;
48 :
49 : /**
50 : * Cached user input for the parameter or the default value
51 : */
52 : std::string cache;
53 : };
54 :
55 : // Description of parameters
56 : using ParamsDescription = std::vector<ParamData>;
57 : // map for command - command description relationship
58 : using DescriptionMap = std::unordered_map<std::string, std::string>;
59 : // Points in a menu
60 : using MenuPoints = std::vector<std::string>;
61 : // map for command - ParamsDescription relationship
62 : using ParamsMap = std::unordered_map<std::string, ParamsDescription>;
63 :
64 : // ------ Common commands short name ---------
65 : const std::string SAVE_CODE = "save";
66 : const std::string SEND_CODE = "send";
67 : const std::string BACK_CODE = "b";
68 :
69 : /**
70 : * Return mapping of Command_name to Command description
71 : * @return DesciptionMap for common commands
72 : */
73 : DescriptionMap getCommonDescriptionMap();
74 :
75 : /**
76 : * Return mapping of Command_name to parameters descriptions
77 : * @param default_ip - default hostname or IP to be used when connecting to
78 : * irohad
79 : * @param default_port - default port to be used when connecting to irohad
80 : * @return ParamsMap with parameters of common commands
81 : */
82 : ParamsMap getCommonParamsMap(const std::string &default_ip,
83 : int default_port);
84 :
85 : /**
86 : * Creates parameters descriptions with empty default/cache values
87 : * @param params - parameters as a vector of prompt messages
88 : * @return ParamsDescription with parameter data
89 : */
90 : ParamsDescription makeParamsDescription(
91 : const std::vector<std::string> ¶ms);
92 :
93 : /**
94 : * Handle error with empty command
95 : */
96 : void handleEmptyCommand();
97 :
98 : /**
99 : * Handle error of unknown command
100 : * @param command - name of unknown command
101 : */
102 : void handleUnknownCommand(std::string &command);
103 :
104 : /**
105 : * Add back option to menu
106 : * @param menu - menu to add the back option
107 : */
108 : void addBackOption(MenuPoints &menu);
109 :
110 : /**
111 : * Is line contains "Go Back" option
112 : * @param line to parse
113 : * @return true if line has command "go back"
114 : */
115 : bool isBackOption(std::string line);
116 :
117 : /**
118 : * Print end of session symbol
119 : */
120 : void printEnd();
121 :
122 : /**
123 : * Print help for cli command.
124 : * @param command - name of the cli command
125 : * @param parameters needed to run the command
126 : */
127 : void printCommandParameters(std::string &command,
128 : const ParamsDescription ¶meters);
129 :
130 : /**
131 : * Pretty Print of menu
132 : * @param message - message to print before menu
133 : * @param menu_points - elements of the menu
134 : */
135 : void printMenu(const std::string &message, MenuPoints menu_points);
136 :
137 : /**
138 : * Get string input from user
139 : * @param message Message to ask user
140 : * @return nullopt if termintaing symbol, else user's input
141 : */
142 : boost::optional<std::string> promptString(const std::string &message);
143 :
144 : /**
145 : * Construct a prompt and get a string input from user
146 : * @param param Parameter to collect the input for
147 : * @return nullopt if termintaing symbol, else user's input
148 : */
149 : boost::optional<std::string> promptString(const ParamData ¶m);
150 :
151 : /**
152 : * Parse parameters in interactive and shortcuted mode.
153 : * Function run interactive mode if in line only the command name is passed.
154 : * Function will parse all needed parameters from line if the line with
155 : * commands is passed, it will print help if there are not enough parameters
156 : * in line.
157 : * @param line - cli line to parse
158 : * @param command_name - command name to print
159 : * @param notes - parameters needed to run the command
160 : * @return vector with needed parameters
161 : */
162 : boost::optional<std::vector<std::string>> parseParams(
163 : std::string line, std::string command_name, ParamsMap ¶ms_map);
164 :
165 : /**
166 : * Add menu point to vector menu
167 : * @param menu_points to add new point
168 : * @param description of the command to add
169 : * @param command_short_name command short name
170 : */
171 : size_t addMenuPoint(std::vector<std::string> &menu_points,
172 : const std::string &description,
173 : const std::string &command_short_name);
174 :
175 : /**
176 : * Get next numerical index in the map.
177 : * Used to build menu
178 : * @tparam K - key type in map
179 : * @tparam V - value type in map
180 : * @param parsers_map - map to process
181 : * @return index for the next menu point
182 : */
183 : template <typename K, typename V>
184 : std::size_t getNextIndex(std::unordered_map<K, V> parsers_map) {
185 : return parsers_map.size() == 0 ? 1 : parsers_map.size();
186 : }
187 :
188 : /**
189 : * Find in unordered map with error reporting.
190 : * Will print unkown command if key not found.
191 : * @tparam K key type
192 : * @tparam V value type
193 : * @param command_name - key to find in the map
194 : * @param params_map - map
195 : * @return nullopt if key not found, value if found
196 : */
197 : template <typename K, typename V>
198 : boost::optional<V &> findInHandlerMap(
199 : K command_name, std::unordered_map<K, V> ¶ms_map) {
200 0 : auto it = params_map.find(command_name);
201 0 : if (it == params_map.end()) {
202 : // Command not found, report error
203 0 : handleUnknownCommand(command_name);
204 0 : return boost::none;
205 : }
206 0 : return it->second;
207 0 : }
208 :
209 : /**
210 : * Parse parameters related to Iroha Peer
211 : * @param params in format: vector of strings
212 : * @return pair if ip and port if formed right, nullopt otherwise
213 : */
214 : boost::optional<std::pair<std::string, uint16_t>> parseIrohaPeerParams(
215 : std::vector<std::string> params,
216 : const std::string &default_ip,
217 : int default_port);
218 :
219 : /**
220 : * Handle parsing routine:
221 : * - find appropriate parser function for the command
222 : * - get input from user for the command
223 : * - trigger specific parser
224 : * @tparam T - expected return type of a parsing function
225 : * @tparam V - type of the parser function in parsers_map
226 : * @tparam C - class type of class_pointer
227 : * @param class_pointer - class pointer that holds parser functions
228 : * @param line - line to parse
229 : * @param parsers_map - map holding parser functions
230 : * @param params_map - map holding descriptions for command parameters
231 : * @return T if parsing successful, nullopt otherwise
232 : */
233 : template <typename T, typename V, typename C>
234 : boost::optional<T> handleParse(
235 : C class_pointer,
236 : std::string &line,
237 : std::unordered_map<std::string, V> &parsers_map,
238 : ParamsMap ¶ms_map) {
239 0 : auto raw_command = parser::parseFirstCommand(line);
240 0 : if (not raw_command) {
241 0 : handleEmptyCommand();
242 0 : return boost::none;
243 : }
244 0 : auto command_name = raw_command.value();
245 0 : auto parser = findInHandlerMap(command_name, parsers_map);
246 0 : if (not parser) {
247 0 : std::cout << "Parser for command not found" << std::endl;
248 0 : return boost::none;
249 : }
250 0 : auto params = parseParams(line, command_name, params_map);
251 0 : if (not params) {
252 0 : std::cout << "Parse params returned no value" << std::endl;
253 0 : return boost::none;
254 : }
255 0 : return (class_pointer->*parser.value())(params.value());
256 0 : }
257 :
258 : /**
259 : * Add new cli command to menu points and menu handlers (parsers)
260 : * @tparam V type of parser functions in parsers_map
261 : * @param menu_points - menu to which points will be added
262 : * @param parsers_map - map holding specific parser functions
263 : * @param command_name - short command name
264 : * @param command_description - description for the command
265 : * @param parser - specific parser for current command
266 : */
267 : template <typename V>
268 : void addCliCommand(MenuPoints &menu_points,
269 : std::unordered_map<std::string, V> &parsers_map,
270 : const std::string &command_name,
271 : const std::string &command_description,
272 : V parser) {
273 : // Add menu point and get the index in menu of current command
274 0 : auto index = std::to_string(
275 0 : addMenuPoint(menu_points, command_description, command_name));
276 : // Add parser for this command
277 0 : parsers_map[index] = parser;
278 0 : parsers_map[command_name] = parser;
279 0 : }
280 :
281 : /**
282 : * Form menu points from given parameters and bind index of the command with
283 : * their parser and parameters
284 : * @tparam V - type of specific parser functions in parsers_map
285 : * @param parsers_map - map holding specific parser functions
286 : * @param paramsMap - map holding descriptions for command parameters
287 : * @param descriptionMap - map holding description of a command
288 : * @return Formed menu points
289 : */
290 : template <typename V>
291 : MenuPoints formMenu(std::unordered_map<std::string, V> &parsers_map,
292 : ParamsMap ¶msMap,
293 : const DescriptionMap descriptionMap) {
294 : // Add menu point and get the index in menu of current command
295 0 : MenuPoints menu_points;
296 0 : std::for_each(descriptionMap.begin(),
297 0 : descriptionMap.end(),
298 : [&parsers_map, &menu_points, ¶msMap](auto val) {
299 0 : auto command_name = val.first;
300 0 : auto command_description = val.second;
301 :
302 0 : auto index = std::to_string(addMenuPoint(
303 0 : menu_points, command_description, command_name));
304 0 : parsers_map[index] = parsers_map.at(command_name);
305 : ;
306 0 : paramsMap[index] = paramsMap.at(command_name);
307 0 : });
308 0 : return menu_points;
309 0 : }
310 :
311 : } // namespace interactive
312 : } // namespace iroha_cli
313 :
314 : #endif // IROHA_CLI_INTERACTIVE_COMMON_CLI_HPP
|