Wire Sysio Wire Sysion 1.0.0
Loading...
Searching...
No Matches
cli.cpp
Go to the documentation of this file.
1#include <fc/rpc/cli.hpp>
2#include <fc/thread/thread.hpp>
3
4#include <iostream>
5
6#ifndef WIN32
7#include <unistd.h>
8#endif
9
10#ifdef HAVE_READLINE
11# include <readline/readline.h>
12# include <readline/history.h>
13// I don't know exactly what version of readline we need. I know the 4.2 version that ships on some macs is
14// missing some functions we require. We're developing against 6.3, but probably anything in the 6.x
15// series is fine
16# if RL_VERSION_MAJOR < 6
17# ifdef _MSC_VER
18# pragma message("You have an old version of readline installed that might not support some of the features we need")
19# pragma message("Readline support will not be compiled in")
20# else
21# warning "You have an old version of readline installed that might not support some of the features we need"
22# warning "Readline support will not be compiled in"
23# endif
24# undef HAVE_READLINE
25# endif
26# ifdef WIN32
27# include <io.h>
28# endif
29#endif
30
31namespace fc { namespace rpc {
32
33static std::vector<std::string>& cli_commands()
34{
35 static std::vector<std::string>* cmds = new std::vector<std::string>();
36 return *cmds;
37}
38
40{
41 if( _run_complete.valid() )
42 {
43 stop();
44 }
45}
46
47variant cli::send_call( api_id_type api_id, string method_name, variants args /* = variants() */ )
48{
49 FC_ASSERT(false);
50}
51
52variant cli::send_callback( uint64_t callback_id, variants args /* = variants() */ )
53{
54 FC_ASSERT(false);
55}
56
57void cli::send_notice( uint64_t callback_id, variants args /* = variants() */ )
58{
59 FC_ASSERT(false);
60}
61
63{
64 cli_commands() = get_method_names(0);
65 _run_complete = fc::async( [&](){ run(); } );
66}
67
69{
70 _run_complete.cancel();
71 _run_complete.wait();
72}
73
75{
76 _run_complete.wait();
77}
78
79void cli::format_result( const string& method, std::function<string(variant,const variants&)> formatter)
80{
81 _result_formatters[method] = formatter;
82}
83
84void cli::set_prompt( const string& prompt )
85{
86 _prompt = prompt;
87}
88
89void cli::run()
90{
91 while( !_run_complete.canceled() )
92 {
93 try
94 {
95 std::string line;
96 try
97 {
98 getline( _prompt.c_str(), line );
99 }
100 catch ( const fc::eof_exception& e )
101 {
102 break;
103 }
104 std::cout << line << "\n";
105 line += char(EOF);
107 if( args.size() == 0 )
108 continue;
109
110 const string& method = args[0].get_string();
111
112 auto result = receive_call( 0, method, variants( args.begin()+1,args.end() ) );
113 auto itr = _result_formatters.find( method );
114 if( itr == _result_formatters.end() )
115 {
116 std::cout << fc::json::to_pretty_string( result ) << "\n";
117 }
118 else
119 std::cout << itr->second( result, args ) << "\n";
120 }
121 catch ( const std::bad_alloc& )
122 {
123 throw;
124 }
125 catch ( const boost::interprocess::bad_alloc& )
126 {
127 throw;
128 }
129 catch ( const fc::exception& e )
130 {
131 std::cout << e.to_detail_string() << "\n";
132 }
133 catch ( const std::exception& e )
134 {
135 std::cout << e.what() << "\n";
136 }
137 }
138}
139
140
141char * dupstr (const char* s) {
142 char *r;
143
144 r = (char*) malloc ((strlen (s) + 1));
145 strcpy (r, s);
146 return (r);
147}
148
149char* my_generator(const char* text, int state)
150{
151 static int list_index, len;
152 const char *name;
153
154 if (!state) {
155 list_index = 0;
156 len = strlen (text);
157 }
158
159 auto& cmd = cli_commands();
160
161 while( list_index < cmd.size() )
162 {
163 name = cmd[list_index].c_str();
164 list_index++;
165
166 if (strncmp (name, text, len) == 0)
167 return (dupstr(name));
168 }
169
170 /* If no names matched, then return NULL. */
171 return ((char *)NULL);
172}
173
174
175static char** cli_completion( const char * text , int start, int end)
176{
177 char **matches;
178 matches = (char **)NULL;
179
180#ifdef HAVE_READLINE
181 if (start == 0)
182 matches = rl_completion_matches ((char*)text, &my_generator);
183 else
184 rl_bind_key('\t',rl_abort);
185#endif
186
187 return (matches);
188}
189
190
191void cli::getline( const fc::string& prompt, fc::string& line)
192{
193 // getting file descriptor for C++ streams is near impossible
194 // so we just assume it's the same as the C stream...
195#ifdef HAVE_READLINE
196#ifndef WIN32
197 if( isatty( fileno( stdin ) ) )
198#else
199 // it's implied by
200 // https://msdn.microsoft.com/en-us/library/f4s0ddew.aspx
201 // that this is the proper way to do this on Windows, but I have
202 // no access to a Windows compiler and thus,
203 // no idea if this actually works
204 if( _isatty( _fileno( stdin ) ) )
205#endif
206 {
207 rl_attempted_completion_function = cli_completion;
208
209 static fc::thread getline_thread("getline");
210 getline_thread.async( [&](){
211 char* line_read = nullptr;
212 std::cout.flush(); //readline doesn't use cin, so we must manually flush _out
213 line_read = readline(prompt.c_str());
214 if( line_read == nullptr )
215 FC_THROW_EXCEPTION( fc::eof_exception, "" );
216 rl_bind_key( '\t', rl_complete );
217 if( *line_read )
218 add_history(line_read);
219 line = line_read;
220 free(line_read);
221 }).wait();
222 }
223 else
224#endif
225 {
226 std::cout << prompt;
227 // sync_call( cin_thread, [&](){ std::getline( *input_stream, line ); }, "getline");
228 fc::getline( fc::cin, line );
229 return;
230 }
231}
232
233} } // namespace fc::rpc
const mie::Vuint & r
Definition bn.cpp:28
std::string name
std::vector< std::string > get_method_names(api_id_type local_api_id=0) const
variant receive_call(api_id_type api_id, const string &method_name, const variants &args=variants()) const
Used to generate a useful error report when an exception is thrown.
Definition exception.hpp:58
std::string to_detail_string(log_level ll=log_level::all) const
static variants variants_from_string(const string &utf8_str, const parse_type ptype=parse_type::legacy_parser, uint32_t max_depth=DEFAULT_MAX_RECURSION_DEPTH)
Definition json.cpp:461
static string to_pretty_string(const variant &v, const yield_function_t &yield, const output_formatting format=output_formatting::stringify_large_ints_and_doubles)
Definition json.cpp:775
virtual variant send_callback(uint64_t callback_id, variants args=variants())
Definition cli.cpp:52
virtual void getline(const fc::string &prompt, fc::string &line)
Definition cli.cpp:191
void start()
Definition cli.cpp:62
virtual variant send_call(api_id_type api_id, string method_name, variants args=variants())
Definition cli.cpp:47
void wait()
Definition cli.cpp:74
void stop()
Definition cli.cpp:68
void format_result(const string &method, std::function< string(variant, const variants &)> formatter)
Definition cli.cpp:79
virtual void send_notice(uint64_t callback_id, variants args=variants())
Definition cli.cpp:57
void set_prompt(const string &prompt)
Definition cli.cpp:84
stores null, int64, uint64, double, bool, string, std::vector<variant>, and variant_object's.
Definition variant.hpp:191
#define FC_THROW_EXCEPTION(EXCEPTION, FORMAT,...)
#define FC_ASSERT(TEST,...)
Checks a condition and throws an assert_exception if the test is FALSE.
char * my_generator(const char *text, int state)
Definition cli.cpp:149
char * dupstr(const char *s)
Definition cli.cpp:141
namespace sysio::chain
Definition authority.cpp:3
std::string string
Definition string.hpp:10
uint32_t api_id_type
Definition api.hpp:46
std::vector< fc::variant > variants
Definition variant.hpp:173
unsigned __int64 uint64_t
Definition stdint.h:136
char * s
size_t len